[wpa_supplicant] Cumulative patch from 9fde14607
Changes include required updates to DPP R2.
Bug: 143479699
Test: Device boots up and connects to WPA3/OWE wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: Regression test Passed (Bug: 143485775)
9fde14607 Allow scans triggered by D-Bus to use MAC address randomization
10f8351d6 D-Bus: Add MAC address randomization endpoints
bb66d4675 Move ownership of MAC address randomization mask to scan params
6c2f70cc6 DPP: Mention ssid and pass parameters for DPP_AUTH_INIT in documentation
1030dec1f JSON: Fix escaping of characters that have MSB=1 with signed char
7800725af dbus: Export OWE capability and OWE BSS key_mgmt
b2ad4e6b2 D-Bus: Fix P2P NULL dereference after interface removal
937644aa2 nl80211: Indicate SUITE_B_192 capa only when CCMP-256/GCMP-256 supported
1b5865a53 SAE: Ignore commit message when waiting for confirm in STA mode
50a2c8c90 Do not indicate possible PSK failure when using SAE
df3b2e22a nl80211: Add STA node details in AP through QCA vendor subcommand
f273b2a5c Add QCA vendor cmd for setting BT coex chain mode
4dc860680 Extend QCA OEM data vendor subcmd to allow use as an event
93a1e275a SAE: Determine H2E vs. looping when restarting SAE auth in AP mode
de580bf6c crypto: Remove unused crypto_bignum_sqrtmod()
9b292a48f SAE: Drop sqrt() alternative from SSWU (H2E)
305369038 wpa_supplicant: Fix arithmetic on void pointer
00ddc1cc2 common: Fix same expression checked twice in fils_key_auth_sk()
327d09aa0 HE: Add 11ax info to ap mode ctrl iface STATUS command
d7678a084 Fix AP Extended Capability length determination
a592f2a9e P2P: Continue listening next request if no post-PD operations
a32acf391 Fix hostapd build with CONFIG_WPA_TRACE but no CONFIG_WPA_TRACE_BFD
b38c8c9cb dbus: Suppress to show NULL string
6807eee9c Interworking: Check NULL string to avoid compiler warning
ec1c0d154 Fix name of DBus interface in defconfig
f73dd0a69 FT-SAE: Add RSNXE into FT MIC
cb9925977 Add RSNXE into (Re)Association Response frames
865721c69 Merge wpa_supplicant and hostapd EAPOL-Key KDE parsers
898b6d58f SAE: Verify that STA negotiated H2E if it claims to support it
74866f537 RSN: Verify RSNXE match between (Re)AssocReq and EAPOL-Key msg 2/4
9981d5bf3 Add RSNXE into AP KDE parser
d3516cad7 Store a copy of Association Request RSNXE in AP mode for later use
6d6c88775 SAE: Add RSNXE in Association Request and EAPOL-Key msg 2/4
8401cdc8d Add RSNXE into IE parser
0b0ed907d WPS: Check SHA256 result success
8dda97c75 QCA vendor command for adding a STA node
b41dc61af Add a new QCA vendor attribute to carry device info for OEM data
bf185bfd5 QCA vendor attributes to indicate BW-based agile spectral capability
1317ea2c0 nl80211: Allow external auth based on SAE/FT-SAE key mgmt
cdb5774f4 FST: Update FST about MAC address change
49e95ee1e AP: Publish only HE capabilities and operation IEs on 6 GHz band
d7c2c5c98 AP: Add initial support for 6 GHz band
a5b2faa71 AP: Add op_class config item to specify 6 GHz channels uniquely
89450024a wpa_supplicant: Pass in operating class for channel validity checks
032c8264d SAE: Check that peer's rejected groups are not enabled in AP
a5dc2a5c1 SAE: H2E version of SAE commit message handling for AP
43b20b437 SAE: Derive H2E PT in AP when starting the AP
444d76f74 SAE: Check that peer's rejected groups are not enabled
cfe1ea5c9 SAE: H2E version of SAE commit message handling for STA
447cd5f2d SAE: Collect list of rejected groups for H2E in STA
05a2fb0d1 SAE: Derive H2E PT in STA before connection
146889e3c RSN: Verify RSNXE match between Beacon/ProbeResp and EAPOL-Key msg 3/4
3134bb13a SAE: Advertise Extended RSN Capabilities when H2E is enabled
293a01f3b SAE: Handle BSS membership selector indication for H2E-only in STA mode
cc0da0ff4 SAE: Advertise BSS membership selector for H2E-only case
85e64e634 SAE: Add sae_pwe configuration parameter for wpa_supplicant
a36e13a7c SAE: Add sae_pwe configuration parameter for hostapd
af4487148 tests: Module test for SAE hash-to-element crypto routines
cf84246eb SAE: Add Rejected Groups element into H2E Commit
efd428529 SAE: Hash algorithm selection for H2E KCK/CN()
aeb022f8e SAE: Implement hash-to-element PT/PWE crypto routines
ecd711407 SAE: Parse Rejected Groups element from H2E SAE commit
86f608486 SAE: Tell sae_parse_commit() whether H2E is used
316156739 SAE: H2E protocol defines
1766e608b wolfSSL: Fix crypto_bignum_sub()
2a1c84f4e crypto: Add more bignum/EC helper functions
9c08bfbd9 DPP: Fix confusing debug entry from Configurator
f7fe05522 SAE: Allow AP behavior for SAE Confirm to be configured
d6a7de60c wpa_cli: Clean up unnecessarily complex CONFIG_MESH use
8b426ab1e wpa_supplicant: Pass AP mode EDMG config to hostapd struct
a82aee1f4 wpa_supplicant: Add support for EDMG channels
35aed771f Indicate EDMG in scan results
f6f8c6ade AP: Show EDMG channel info in STATUS output
241dd76cf hostapd: Check EDMG configuration against capability
dc3457cc4 hostapd: Check usability of EDMG channel
bebd91e9c Add EDMG parameters to set_freq functions
fdd0fef2c EDMG: Helper functions for parameter encoding/checking
e8ff22f47 wpa_supplicant: Add EDMG channel configuration parameters
5c5ff22ef hostapd: Add EDMG channel configuration parameters
dda5d9e31 nl80211: Add support for EDMG channels
a19913c17 IEEE P802.11ay/D4.0 defines for EDMG
c34917403 MBO/OCE: Update disable_mbo_oce flag after association
b719a1568 DPP2: Parse AKM suite selector version of akm node
68fea9603 DPP2: Allow Configurator to use AKM suite selectors in Config Object
52d469de1 DPP2: Support multiple Config Objects in Enrollee
7eb06a336 DPP2: Allow multiple Config Objects to be build on Configurator
99918e069 DPP: Cleaned up netrole indication for config object building
e0d22c842 FILS+FT: Fix MFPR flag in RSNE during FILS exchange for FT
d0a4ed6a1 Allow SAE to be used in wpa_supplicant AP mode
7846e8d60 NetBSD: Fix compile
2e06cef80 MBO/OCE: Work around misbehaving MBO/OCE APs that use RSN without PMF
722c7d195 wlantest: Process VLAN tagged Data frames
83b83b461 nl80211: Migrate to current netlink key message format
7a4b01c87 AP: Provide correct keyid to wpa_send_eapol() for EAPOL-Key msg 3/4
a3ebf7175 BSD: Add support for route(4) message filtering
d9286d099 ACS: Stop before scan if no channels in chanlist are available
f32aa244e DPP: Debug print configRequest bandSupport on Configurator
8f8c423a5 DPP: Add bandSupport JSON array into config request
6d3dc9ba1 mka: Check OLPN for exhaustion on SAKuse decode
84851007d mka: Check OLPN for exhaustion on SAKuse encode
547ba732d mka: Clear out old/latest key values on CHANGE in CP state machine
536a7cfcf mka: Don't set newSAK to FALSE on ABANDON in CP state machine
0fedfba2e mka: Change RECEIVE and RETIRE states to match the standard
3f2641e7a Fix wpa_supplicant build with CONFIG_PCSC=y
5a5639b06 DPP: Allow name and mudurl to be configured for Config Request
3394def5a More consistent SA check for unexpected Data frames
16ef233bf DPP2: Connection status result (Enrollee)
b10e01a79 DPP2: Connection status result (Configurator)
e501a2eb5 DPP2: Connection status result defines
cc8399528 DPP2: Move dpp_build_conf_result() to be within ifdef block
3a6736fe8 DPP2: Fix a memory leak on error path for Config Result
21dc1627f wpa_supplicant: Don't return an error when successfully parsing WMM rules
8214b45ba P2P: Use latest BSS entry if multiple P2P Device Addr matches found
dc6c3be4e wpa_supplicant: Add support for 60 GHz band channels 5 and 6
018edec9b Remove IAPP functionality from hostapd
d86d66dc0 AP: Silently ignore management frame from unexpected source address
a84bf4438 HE: Send the AP's OBSS PD settings to the kernel
262b71eea Sync with mac80211-next.git include/uapi/linux/nl80211.h
8788a314d WPS: Update MAC address on address changes
39042d7f7 os_sleep: Use nanosleep for POSIX versions 2008 and higher
a69742c2f wpa_cli: Do not pick p2p-dev-* interfaces by default
d842e00bd SAE: Return result from confirm CN() operation to the caller
a8bfc6fff FILS: Update connect params after sending connection notification
0df82a3da Correct the type/usage of QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST
6bf6c6fec DPP: Fix hostapd build dependencies for DPP-only build
1eff2e7bf DPP2: Fix wpa_supplicant build dependencies for CONFIG_AP=y build
d2bae5763 DPP: Fix wpa_supplicant build dependencies for DPP-only build
7d2ed8bae Remove CONFIG_IEEE80211W build parameter
022926187 DFS offload: Fix hostapd state and CAC info in STATUS output
4d78ba990 EAP-TEAP peer: Clear Phase 2 EAP method on new Identity exchange
681618246 EAP-TEAP peer: Add support for machine credentials using certificates
ebee8232d Do not try to include net/ethernet.h in MinGW/Windows builds
bf15b1559 Fix Windows error code definition workaround
043de65f1 EAP peer config: Move ocsp param to phase1/phase2
8d76e0ad7 EAP server: Configurable maximum number of authentication message rounds
b99c4cadb EAP peer: Move certificate configuration params into shared struct
6e711e7ab mesh: Do not enable HE on 5 GHz without VHT
0497e4148 HE: Fix HE Capabilities element size
a2e0cc9e0 Add nl80211 vendor ACS trigger reasons related to interference
69e8e7817 HS 2.0: Do not add two copies of OSEN element into Beacon/Probe Resp
a762ba8b1 HS 2.0 AP: Do not mandate PMF for HS 2.0 Indication in open OSU network
e49ce2990 IEEE 802.1X authenticator: Coding style cleanup
31aaddc90 Clean up IEEE 802.1X authentication debug messages for EAP code
71419119f EAP-TEAP peer: Fix protected indication of inner EAP method failure
93cd29d2b EAP-TEAP server: Add support for requiring user and machine credentials
c38c62ff7 wlantest: Derive PMK-R1 and PTK for FT protocol cases
c41936566 EAP-TEAP peer: Add support for machine authentication
c724a0a16 EAP peer: Add a concept of a separate machine credential
9ce3bfaf4 RADIUS server: Abort startup on allocation failures
fa1f0751c RADIUS server: Use struct eap_config to avoid duplicated definitions
a00cb1b1f EAP-TEAP server: Fix eap_teap_pac_no_inner configuration
986033ff3 EAP-TEAP server: Fix Crypto-Binding check in PAC no-inner-auth case
e54cfbb56 EAP-TEAP server: Allow a specific Identity-Type to be requested/required
f186ec54c EAP-TEAP peer: Support Identity-Type TLV
cc661c160 EAP-TEAP: Add parsing and generation routines for Identity-Type TLV
100b2edb2 OpenSSL: Write peer certificate chain details in debug log
7eb157f1e EAP: Increase the maximum number of message exchanges
822e7c66a EAP server: Use struct eap_config to avoid duplicated definitions
62af2b18f EAP-TEAP peer: Support vendor EAP method in Phase 2
aba8dc82f EAP-PEAP server: Support vendor EAP types in Phase 2
357c1062d EAP-FAST peer: Support vendor EAP method in Phase 2
f32f76231 EAP-FAST server: Support vendor EAP types in Phase 2
887d8703b EAP-PEAP peer: Support vendor EAP method in Phase 2
f2ef4f255 EAP peer: Allow VENDOR-TEST method in Phase 2
5ddbd9e96 EAP-TTLS peer: Support vendor EAP method in Phase 2
5e94e7f23 EAP-TTLS server: Support vendor EAP types in Phase 2
5f2301a6d Replace EapType typedef with enum eap_type
76ddfae6e EAP-TEAP server: Testing mechanism for Result TLV in a separate message
4c327146f EAP-TEAP peer: Allow Result TLV without Crypto-Binding TLV
128d46be9 EAP-TEAP: Add parsing of Error TLV
234489efd EAP-TEAP server: Require Intermediate-Result TLV even with Result TLV
0f7c91f2b EAP-TEAP peer: Add Intermediate-Result TLV with Crypto-Binding TLV
a66e53c41 EAP-TEAP: Fix TLS-PRF for TLS ciphersuites that use SHA384
52069c7ef Add TLS-PRF using HMAC with P_SHA384 for TEAP
a647a0ad7 Extend server certificate TOD policy reporting to include TOD-TOFU
346d10cf8 SAE: Conditionally set PMKID while notifying the external auth status
b7cd64876 SAE: Use BSSID stored in ext_auth_bssid for set_pmk
e0b331d89 OWE: Update connect params with new DH attributes to the driver
c574a3ff1 nl80211: Request update connection params only for drivers with SME
528f263c4 FT: Reject over-the-DS response with MFPC=0 if PMF is required
ae05b6a21 RSN: Do not allow connection to proceed without MFPC=1 if PMF required
ded56f2fa FT: Fix MFPR flag in RSNE during FT protocol
0028d627c OCE: Mandate PMF for WPA2 association with OCE AP
84ebc759a HS 2.0: Match credentials based on required_roaming_consortium
d2b208384 SAE: Allow PMKID to be added into Association Request frame following SAE
2ca23faf1 Make wpa_insert_pmkid() more generic
05822609d HE: MCS size is always a minimum of 4 bytes
df4f95998 nl80211: Don't force VHT channel definition with HE
dd0153fce Check for LEAP before doing FT
6126e5f97 Fix a typo in hostapd config documentation
698a0067c Fix check_crl_strict documentation
485dd425b Add QCA vendor command for avoid frequency feature
6ae1247bf Update QCA vendor attributes for 6 GHz band support
aa23ece3d Add QCA vendor channel attribute to restart AP
85508ecf6 Add QCA vendor command to configure ACS policy
2395fdb67 Add QCA vendor attributes to enhance roaming configuration
1425caac2 Rename qca_wlan_vendor_attr_roam_subcmd to represent subcmds
f13119631 Document the attributes used by QCA_NL80211_VENDOR_SUBCMD_ROAM
b0b25c5bb Clear external eapSuccess setting in driver-authorized cases
fa1d5ec18 The master branch is now used for v2.10 development
ca8c2bd28 Preparations for v2.8 release
3263fca28 Set the default scan IEs on interface restart
d776bf8c6 EAP-TEAP peer: Fix fragmentation of final message
1c7e61a35 wolfssl: Avoid void pointer arithmetic
7122a02fa SAE: Fix order_len for FFC groups
422e73d62 DPP: Indicate authentication success on ConfReqRX if needed
d001fe31a OpenSSL: Handle EVP_PKEY_derive() secret_len changes for ECDH
29ef1c5ee DPP: Use a common helper function for ECDH operations
ac734a342 SAE: Fix KCK, PMK, and PMKID derivation for groups 22, 23, 24
c65168ccd OpenSSL: Fix crypto_bignum_to_bin() with padlen == 0
cb28bd52e nl80211: Use separate flag for 4-way handshake offload
6bb11c7a4 EAP-SIM/AKA server: Allow pseudonym/fast reauth to be disabled
c1b236521 EAP-SIM/AKA: Do not allow anonymous@realm "pseudonym" to be cleared
cc2fd9425 D-Bus: Demote timeout/flush messages to MSG_MSGDUMP
3b726df82 nl80211: Missing sysctl flags aren't fatal
f4111ff3d Extra RADIUS request attributes from SQLite
74707def8 Move hostapd_parse_radius_attr() into ap_config.c
1e5ea68d1 mka: Accept last two used MNs in Peers List of a received MKPDU
013686403 P2P: Pass HE flag to GO negotiation result
876c5eaa6 dragonfly: Disable use of groups using Brainpool curves
968520da8 nl80211: Add WMM parameters while updating TDLS peer entry
5a511924b wpa_cli: Add support to process DPP action events in action script
64e37be94 Avoid nested enum wpas_mode declaration to allow C++ compilation
fe2e1edf4 EAP-SIM server: Avoid void pointer arithmetic
cfc9ebea0 EAP-AKA server: Avoid void pointer arithmetic
bd0414043 trace: Avoid void pointer arithmetic
fc03ea2c1 DPP: Avoid void pointer arithmetic
d1b1f9fa9 Report WPA/RSN protocol and AKM suite selector in STA MIB
43aafef8d Add missed wpa_akm_to_suite() selectors
bfb6a482f dragonfly: SAE/EAP-pwd min PWE derivation iteration count to shared code
226da33d7 EAP-pwd peer: Configurable set of groups with reduced default
6a4406c01 Add QCA vendor attributes for ELNA bypass
176c133e9 Add a vendor attribute to configure disconnect IEs
123895228 Add QCA vendor command to support OEM data
Change-Id: Iaa497edcda7c5dcdad19db9d09ab09ef74e508bd
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index ecfcaf5..24f1403 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -216,18 +216,12 @@
L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
-ifdef CONFIG_IAPP
-L_CFLAGS += -DCONFIG_IAPP
-OBJS += src/ap/iapp.c
-endif
-
ifdef CONFIG_RSN_PREAUTH
L_CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_HS20
-NEED_AES_OMAC1=y
CONFIG_PROXYARP=y
endif
@@ -237,8 +231,6 @@
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -249,24 +241,14 @@
ifdef CONFIG_OCV
L_CFLAGS += -DCONFIG_OCV
OBJS += src/common/ocv.c
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-L_CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += src/ap/wpa_auth_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
NEED_AES_SIV=y
NEED_ETH_P_OUI=y
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -289,7 +271,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -424,7 +405,6 @@
L_CFLAGS += -DEAP_SERVER_AKA
OBJS += src/eap_server/eap_server_aka.c
CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -449,7 +429,6 @@
ifdef CONFIG_EAP_PSK
L_CFLAGS += -DEAP_SERVER_PSK
OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -465,14 +444,11 @@
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_SERVER_PWD
OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -505,6 +481,8 @@
TLS_FUNCS=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
NEED_AES_UNWRAP=y
endif
@@ -522,7 +500,6 @@
OBJS += src/wps/wps_enrollee.c
OBJS += src/wps/wps_registrar.c
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -571,9 +548,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
@@ -650,7 +627,6 @@
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -664,7 +640,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
@@ -722,7 +697,6 @@
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -817,12 +791,10 @@
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -830,9 +802,7 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
AESOBJS += src/crypto/aes-omac1.c
-endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
@@ -920,7 +890,6 @@
endif
endif
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -934,6 +903,9 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
OBJS += src/crypto/sha256-kdf.c
endif
@@ -943,7 +915,6 @@
ifdef NEED_HMAC_SHA512_KDF
OBJS += src/crypto/sha512-kdf.c
endif
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 327ee3b..6c4410e 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,29 @@
ChangeLog for hostapd
+2019-08-07 - v2.9
+ * SAE changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * EAP-pwd changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * fixed FT-EAP initial mobility domain association using PMKSA caching
+ * added configuration of airtime policy
+ * fixed FILS to and RSNE into (Re)Association Response frames
+ * fixed DPP bootstrapping URI parser of channel list
+ * added support for regulatory WMM limitation (for ETSI)
+ * added support for MACsec Key Agreement using IEEE 802.1X/PSK
+ * added experimental support for EAP-TEAP server (RFC 7170)
+ * added experimental support for EAP-TLS server with TLS v1.3
+ * added support for two server certificates/keys (RSA/ECC)
+ * added AKMSuiteSelector into "STA <addr>" control interface data to
+ determine with AKM was used for an association
+ * added eap_sim_id parameter to allow EAP-SIM/AKA server pseudonym and
+ fast reauthentication use to be disabled
+ * fixed an ECDH operation corner case with OpenSSL
+
2019-04-21 - v2.8
* SAE changes
- added support for SAE Password Identifier
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 2a6bd7a..955e278 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -121,6 +121,7 @@
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
@@ -248,18 +249,12 @@
CFLAGS += -DCONFIG_CTRL_IFACE
endif
-ifdef CONFIG_IAPP
-CFLAGS += -DCONFIG_IAPP
-OBJS += ../src/ap/iapp.o
-endif
-
ifdef CONFIG_RSN_PREAUTH
CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_HS20
-NEED_AES_OMAC1=y
CONFIG_PROXYARP=y
endif
@@ -269,8 +264,6 @@
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -281,24 +274,14 @@
ifdef CONFIG_OCV
CFLAGS += -DCONFIG_OCV
OBJS += ../src/common/ocv.o
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += ../src/ap/wpa_auth_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
NEED_AES_SIV=y
NEED_ETH_P_OUI=y
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -322,7 +305,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -391,7 +373,6 @@
ifdef CONFIG_ERP
CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -452,7 +433,6 @@
CFLAGS += -DEAP_SERVER_AKA
OBJS += ../src/eap_server/eap_server_aka.o
CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -477,7 +457,6 @@
ifdef CONFIG_EAP_PSK
CFLAGS += -DEAP_SERVER_PSK
OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -493,14 +472,11 @@
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
CFLAGS += -DEAP_SERVER_PWD
OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -533,6 +509,8 @@
TLS_FUNCS=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
NEED_AES_UNWRAP=y
endif
@@ -550,7 +528,6 @@
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -599,9 +576,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
@@ -687,7 +664,6 @@
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), wolfssl)
@@ -701,7 +677,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_wolfssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lwolfssl -lm
LIBS_h += -lwolfssl -lm
@@ -723,7 +698,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
@@ -787,7 +761,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -864,7 +837,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -925,12 +897,10 @@
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += ../src/crypto/aes-siv.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += ../src/crypto/aes-ctr.o
@@ -938,13 +908,11 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
-ifdef NEED_AES_OMAC1
ifneq ($(CONFIG_TLS), linux)
ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
-endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1050,7 +1018,6 @@
endif
endif
-ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1068,6 +1035,9 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += ../src/crypto/sha384-tlsprf.o
+endif
ifdef NEED_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
endif
@@ -1077,7 +1047,6 @@
ifdef NEED_HMAC_SHA512_KDF
OBJS += ../src/crypto/sha512-kdf.o
endif
-endif
ifdef NEED_SHA384
CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1345,7 +1314,6 @@
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/android.config b/hostapd/android.config
index 4502a60..f19f62f 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -38,18 +38,9 @@
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-#CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
#CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index df41f14..40066ad 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -24,14 +24,6 @@
#include "config_file.h"
-#ifndef CONFIG_NO_RADIUS
-#ifdef EAP_SERVER
-static struct hostapd_radius_attr *
-hostapd_parse_radius_attr(const char *value);
-#endif /* EAP_SERVER */
-#endif /* CONFIG_NO_RADIUS */
-
-
#ifndef CONFIG_NO_VLAN
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
@@ -660,75 +652,6 @@
}
-static struct hostapd_radius_attr *
-hostapd_parse_radius_attr(const char *value)
-{
- const char *pos;
- char syntax;
- struct hostapd_radius_attr *attr;
- size_t len;
-
- attr = os_zalloc(sizeof(*attr));
- if (attr == NULL)
- return NULL;
-
- attr->type = atoi(value);
-
- pos = os_strchr(value, ':');
- if (pos == NULL) {
- attr->val = wpabuf_alloc(1);
- if (attr->val == NULL) {
- os_free(attr);
- return NULL;
- }
- wpabuf_put_u8(attr->val, 0);
- return attr;
- }
-
- pos++;
- if (pos[0] == '\0' || pos[1] != ':') {
- os_free(attr);
- return NULL;
- }
- syntax = *pos++;
- pos++;
-
- switch (syntax) {
- case 's':
- attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
- break;
- case 'x':
- len = os_strlen(pos);
- if (len & 1)
- break;
- len /= 2;
- attr->val = wpabuf_alloc(len);
- if (attr->val == NULL)
- break;
- if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
- wpabuf_free(attr->val);
- os_free(attr);
- return NULL;
- }
- break;
- case 'd':
- attr->val = wpabuf_alloc(4);
- if (attr->val)
- wpabuf_put_be32(attr->val, atoi(pos));
- break;
- default:
- os_free(attr);
- return NULL;
- }
-
- if (attr->val == NULL) {
- os_free(attr);
- return NULL;
- }
-
- return attr;
-}
-
static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
@@ -788,12 +711,10 @@
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
@@ -2624,6 +2545,10 @@
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
bss->tls_flags = parse_tls_flags(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds") == 0) {
+ bss->max_auth_rounds = atoi(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds_short") == 0) {
+ bss->max_auth_rounds_short = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@@ -2697,6 +2622,10 @@
bss->eap_teap_auth = val;
} else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
bss->eap_teap_pac_no_inner = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_separate_result") == 0) {
+ bss->eap_teap_separate_result = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_id") == 0) {
+ bss->eap_teap_id = atoi(pos);
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
@@ -2706,6 +2635,8 @@
bss->eap_sim_db_timeout = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
bss->eap_sim_aka_result_ind = atoi(pos);
+ } else if (os_strcmp(buf, "eap_sim_id") == 0) {
+ bss->eap_sim_id = atoi(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
@@ -2781,8 +2712,7 @@
bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
} else if (os_strcmp(buf, "iapp_interface") == 0) {
- bss->ieee802_11f = 1;
- os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
+ wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used");
#endif /* CONFIG_IAPP */
} else if (os_strcmp(buf, "own_ip_addr") == 0) {
if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
@@ -2909,6 +2839,9 @@
a = a->next;
a->next = attr;
}
+ } else if (os_strcmp(buf, "radius_req_attr_sqlite") == 0) {
+ os_free(bss->radius_req_attr_sqlite);
+ bss->radius_req_attr_sqlite = os_strdup(pos);
} else if (os_strcmp(buf, "radius_das_port") == 0) {
bss->radius_das_port = atoi(pos);
} else if (os_strcmp(buf, "radius_das_client") == 0) {
@@ -3203,6 +3136,8 @@
}
} 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
@@ -3217,6 +3152,10 @@
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",
@@ -3444,7 +3383,6 @@
}
} else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
conf->use_driver_iface_addr = atoi(pos);
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
@@ -3475,7 +3413,6 @@
line);
return 1;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
} else if (os_strcmp(buf, "ocv") == 0) {
bss->ocv = atoi(pos);
@@ -4247,6 +4184,10 @@
}
} 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) {
@@ -4396,6 +4337,12 @@
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
#ifdef CONFIG_DPP
+ } else if (os_strcmp(buf, "dpp_name") == 0) {
+ os_free(bss->dpp_name);
+ bss->dpp_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "dpp_mud_url") == 0) {
+ os_free(bss->dpp_mud_url);
+ bss->dpp_mud_url = os_strdup(pos);
} else if (os_strcmp(buf, "dpp_connector") == 0) {
os_free(bss->dpp_connector);
bss->dpp_connector = os_strdup(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 0f6dfa1..2c44d1e 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -130,7 +130,6 @@
}
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
const char *txtaddr)
@@ -149,7 +148,6 @@
return 0;
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1098,7 +1096,6 @@
}
#endif /* CONFIG_FILS */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
if (os_snprintf_error(end - pos, ret))
@@ -1111,7 +1108,6 @@
return pos - buf;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
ret = os_snprintf(pos, end - pos, "SAE ");
@@ -1428,6 +1424,11 @@
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);
}
}
@@ -2109,7 +2110,6 @@
if (hwaddr_aton(cmd, addr))
return -1;
-#ifdef CONFIG_IEEE80211W
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
if (hapd->last_igtk_alg == WPA_ALG_NONE)
return -1;
@@ -2133,7 +2133,6 @@
hapd->last_igtk,
hapd->last_igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
if (is_broadcast_ether_addr(addr)) {
if (hapd->last_gtk_alg == WPA_ALG_NONE)
@@ -3032,13 +3031,11 @@
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
reply_len = -1;
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 01871c9..1a3d9f9 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -44,15 +44,9 @@
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f2d5873..4cbe451 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -41,7 +41,6 @@
# bit 2 (4) = RADIUS
# bit 3 (8) = WPA
# bit 4 (16) = driver interface
-# bit 5 (32) = IAPP
# bit 6 (64) = MLME
#
# Levels (minimum value for logged events):
@@ -147,7 +146,8 @@
# 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.
@@ -164,6 +164,12 @@
# 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
#
@@ -800,6 +806,11 @@
#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
@@ -1012,7 +1023,7 @@
#check_crl=1
# Specify whether to ignore certificate CRL validity time mismatches with
-# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
+# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID.
#
# 0 = ignore errors
# 1 = do not ignore errors (default)
@@ -1081,6 +1092,12 @@
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
#tls_flags=[flag1][flag2]...
+# Maximum number of EAP message rounds with data (default: 100)
+#max_auth_rounds=100
+
+# Maximum number of short EAP message rounds (default: 50)
+#max_auth_rounds_short=50
+
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@@ -1201,10 +1218,31 @@
# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
#eap_teap_pac_no_inner=0
+# EAP-TEAP behavior with Result TLV
+# 0 = include with Intermediate-Result TLV (default)
+# 1 = send in a separate message (for testing purposes)
+#eap_teap_separate_result=0
+
+# EAP-TEAP identities
+# 0 = allow any identity type (default)
+# 1 = require user identity
+# 2 = require machine identity
+# 3 = request user identity; accept either user or machine identity
+# 4 = request machine identity; accept either user or machine identity
+# 5 = require both user and machine identity
+#eap_teap_id=0
+
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
# (default: 0 = disabled).
#eap_sim_aka_result_ind=1
+# EAP-SIM and EAP-AKA identity options
+# 0 = do not use pseudonyms or fast reauthentication
+# 1 = use pseudonyms, but not fast reauthentication
+# 2 = do not use pseudonyms, but use fast reauthentication
+# 3 = use pseudonyms and use fast reauthentication (default)
+#eap_sim_id=3
+
# Trusted Network Connect (TNC)
# If enabled, TNC validation will be required before the peer is allowed to
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
@@ -1216,11 +1254,6 @@
# Whether to enable ERP on the EAP server.
#eap_server_erp=1
-##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
-
-# Interface to be used for IAPP broadcast packets
-#iapp_interface=eth0
-
##### RADIUS client configuration #############################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
@@ -1384,6 +1417,17 @@
# Operator-Name = "Operator"
#radius_acct_req_attr=126:s:Operator
+# If SQLite support is included, path to a database from which additional
+# RADIUS request attributes are extracted based on the station MAC address.
+#
+# The schema for the radius_attributes table is:
+# id | sta | reqtype | attr : multi-key (sta, reqtype)
+# id = autonumber
+# sta = station MAC address in `11:22:33:44:55:66` format.
+# type = `auth` | `acct` | NULL (match any)
+# attr = existing config file format, e.g. `126:s:Test Operator`
+#radius_req_attr_sqlite=radius_attr.sqlite
+
# Dynamic Authorization Extensions (RFC 5176)
# This mechanism can be used to allow dynamic changes to user session based on
# commands from a RADIUS server (or some other disconnect client that has the
@@ -1686,7 +1730,7 @@
#sae_anti_clogging_threshold=5
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
-# The offending SAe peer will be disconnected if more than this many
+# The offending SAE peer will be disconnected if more than this many
# synchronization errors happen.
#sae_sync=5
@@ -1711,6 +1755,21 @@
# 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
@@ -2133,6 +2192,20 @@
# Allow cross connection
#allow_cross_connection=1
+##### Device Provisioning Protocol (DPP) ######################################
+
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
+#dpp_connector
+#dpp_netaccesskey
+#dpp_netaccesskey_expiry
+#dpp_csign
+#dpp_controller
+
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
@@ -2620,6 +2693,19 @@
# 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/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 0460243..42edb7b 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -401,7 +401,6 @@
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -414,7 +413,6 @@
snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1542,10 +1540,8 @@
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
"<addr> = get taxonomy signature for a station" },
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
"<addr> = send SA Query to a station" },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
diff --git a/hostapd/main.c b/hostapd/main.c
index 11a1515..f08d60e 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -83,9 +83,6 @@
case HOSTAPD_MODULE_DRIVER:
module_str = "DRIVER";
break;
- case HOSTAPD_MODULE_IAPP:
- module_str = "IAPP";
- break;
case HOSTAPD_MODULE_MLME:
module_str = "MLME";
break;
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 48f8f23..54e48a0 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -15,11 +15,9 @@
CFLAGS += -DCONFIG_INTERWORKING
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R_AP
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_WPS
CFLAGS += -DCONFIG_PROXYARP
CFLAGS += -DCONFIG_IPV6
-CFLAGS += -DCONFIG_IAPP
CFLAGS += -DCONFIG_AIRTIME_POLICY
LIB_OBJS= \
@@ -42,7 +40,6 @@
hostapd.o \
hs20.o \
hw_features.o \
- iapp.o \
ieee802_11_auth.o \
ieee802_11.o \
ieee802_11_ht.o \
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 0aacc3c..9fc1886 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -97,6 +97,9 @@
msg) < 0)
goto fail;
+ if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
+ goto fail;
+
if (sta) {
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 11178a1..f12539f 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -942,6 +942,12 @@
}
*freq = 0;
+ if (params.freqs == freq) {
+ wpa_printf(MSG_ERROR, "ACS: No available channels found");
+ os_free(params.freqs);
+ return -1;
+ }
+
iface->scan_cb = acs_scan_complete;
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index a061bd8..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"
@@ -78,6 +79,7 @@
bss->radius_server_auth_port = 1812;
bss->eap_sim_db_timeout = 1;
+ bss->eap_sim_id = 3;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
@@ -85,11 +87,9 @@
bss->pwd_group = 19; /* ECC: GF(p=256) */
-#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
bss->eap_fast_prov = 3;
@@ -134,6 +134,9 @@
* completed and tested with other implementations. */
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+ bss->max_auth_rounds = 100;
+ bss->max_auth_rounds_short = 50;
+
bss->send_probe_response = 1;
#ifdef CONFIG_HS20
@@ -432,10 +435,50 @@
}
+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 "
@@ -476,7 +519,76 @@
}
-static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value)
+{
+ const char *pos;
+ char syntax;
+ struct hostapd_radius_attr *attr;
+ size_t len;
+
+ attr = os_zalloc(sizeof(*attr));
+ if (!attr)
+ return NULL;
+
+ attr->type = atoi(value);
+
+ pos = os_strchr(value, ':');
+ if (!pos) {
+ attr->val = wpabuf_alloc(1);
+ if (!attr->val) {
+ os_free(attr);
+ return NULL;
+ }
+ wpabuf_put_u8(attr->val, 0);
+ return attr;
+ }
+
+ pos++;
+ if (pos[0] == '\0' || pos[1] != ':') {
+ os_free(attr);
+ return NULL;
+ }
+ syntax = *pos++;
+ pos++;
+
+ switch (syntax) {
+ case 's':
+ attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+ break;
+ case 'x':
+ len = os_strlen(pos);
+ if (len & 1)
+ break;
+ len /= 2;
+ attr->val = wpabuf_alloc(len);
+ if (!attr->val)
+ break;
+ if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+ wpabuf_free(attr->val);
+ os_free(attr);
+ return NULL;
+ }
+ break;
+ case 'd':
+ attr->val = wpabuf_alloc(4);
+ if (attr->val)
+ wpabuf_put_be32(attr->val, atoi(pos));
+ break;
+ default:
+ os_free(attr);
+ return NULL;
+ }
+
+ if (!attr->val) {
+ os_free(attr);
+ return NULL;
+ }
+
+ return attr;
+}
+
+
+void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
{
struct hostapd_radius_attr *prev;
@@ -572,6 +684,9 @@
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);
}
}
@@ -608,6 +723,9 @@
#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);
@@ -625,6 +743,7 @@
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
+ os_free(conf->radius_req_attr_sqlite);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
@@ -769,6 +888,8 @@
hostapd_config_free_fils_realms(conf);
#ifdef CONFIG_DPP
+ os_free(conf->dpp_name);
+ os_free(conf->dpp_mud_url);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index eebf898..2a0c984 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -99,6 +99,7 @@
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 @@
char *identifier;
u8 peer_addr[ETH_ALEN];
int vlan_id;
+ struct sae_pt *pt;
};
struct dpp_controller_conf {
@@ -301,6 +303,7 @@
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
struct hostapd_radius_attr *radius_acct_req_attr;
+ char *radius_req_attr_sqlite;
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
@@ -324,10 +327,6 @@
int erp_send_reauth_start;
char *erp_domain;
- int ieee802_11f; /* use IEEE 802.11f (IAPP) */
- char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
- * frames */
-
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
@@ -346,14 +345,12 @@
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int wpa_key_mgmt;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -414,6 +411,8 @@
unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
@@ -428,7 +427,10 @@
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ int eap_teap_id;
int eap_sim_aka_result_ind;
+ int eap_sim_id;
int tnc;
int fragment_size;
u16 pwd_group;
@@ -649,6 +651,8 @@
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;
@@ -707,6 +711,8 @@
int broadcast_deauth;
#ifdef CONFIG_DPP
+ char *dpp_name;
+ char *dpp_mud_url;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
@@ -869,7 +875,10 @@
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;
@@ -1074,6 +1083,7 @@
int hostapd_mac_comp(const void *a, const void *b);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
@@ -1092,9 +1102,11 @@
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value);
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 c0ededa..204274f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -107,6 +107,10 @@
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;
@@ -305,9 +309,7 @@
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
-#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, ¶ms);
}
@@ -348,7 +350,7 @@
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);
}
@@ -540,7 +542,8 @@
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)
@@ -548,7 +551,8 @@
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,
@@ -810,7 +814,8 @@
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 @@
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/authsrv.c b/src/ap/authsrv.c
index b3d9107..8e12daf 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -110,27 +110,10 @@
srv.auth_port = conf->radius_server_auth_port;
srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
- srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
- srv.ssl_ctx = hapd->ssl_ctx;
- srv.msg_ctx = hapd->msg_ctx;
- srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
- srv.eap_fast_a_id = conf->eap_fast_a_id;
- srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
- srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
- srv.eap_fast_prov = conf->eap_fast_prov;
- srv.pac_key_lifetime = conf->pac_key_lifetime;
- srv.pac_key_refresh_time = conf->pac_key_refresh_time;
- srv.eap_teap_auth = conf->eap_teap_auth;
- srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
- srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- srv.tnc = conf->tnc;
- srv.wps = hapd->wps;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
- srv.pwd_group = conf->pwd_group;
- srv.server_id = conf->server_id ? conf->server_id : "hostapd";
srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
@@ -141,10 +124,8 @@
srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
- srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
- srv.tls_session_lifetime = conf->tls_session_lifetime;
- srv.tls_flags = conf->tls_flags;
+ srv.eap_cfg = hapd->eap_cfg;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -192,6 +173,60 @@
#endif /* EAP_TLS_FUNCS */
+static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
+{
+ struct eap_config *cfg;
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (!cfg)
+ return NULL;
+
+ cfg->eap_server = hapd->conf->eap_server;
+ cfg->ssl_ctx = hapd->ssl_ctx;
+ cfg->msg_ctx = hapd->msg_ctx;
+ cfg->eap_sim_db_priv = hapd->eap_sim_db_priv;
+ cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ cfg->tls_flags = hapd->conf->tls_flags;
+ cfg->max_auth_rounds = hapd->conf->max_auth_rounds;
+ cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short;
+ if (hapd->conf->pac_opaque_encr_key)
+ cfg->pac_opaque_encr_key =
+ os_memdup(hapd->conf->pac_opaque_encr_key, 16);
+ if (hapd->conf->eap_fast_a_id) {
+ cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id,
+ hapd->conf->eap_fast_a_id_len);
+ cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+ }
+ if (hapd->conf->eap_fast_a_id_info)
+ cfg->eap_fast_a_id_info =
+ os_strdup(hapd->conf->eap_fast_a_id_info);
+ cfg->eap_fast_prov = hapd->conf->eap_fast_prov;
+ cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime;
+ cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+ cfg->eap_teap_auth = hapd->conf->eap_teap_auth;
+ cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
+ cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
+ cfg->eap_teap_id = hapd->conf->eap_teap_id;
+ cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+ cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->tnc = hapd->conf->tnc;
+ cfg->wps = hapd->wps;
+ cfg->fragment_size = hapd->conf->fragment_size;
+ cfg->pwd_group = hapd->conf->pwd_group;
+ cfg->pbc_in_m1 = hapd->conf->pbc_in_m1;
+ if (hapd->conf->server_id) {
+ cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id);
+ cfg->server_id_len = os_strlen(hapd->conf->server_id);
+ } else {
+ cfg->server_id = (u8 *) os_strdup("hostapd");
+ cfg->server_id_len = 7;
+ }
+ cfg->erp = hapd->conf->eap_server_erp;
+
+ return cfg;
+}
+
+
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
@@ -272,6 +307,14 @@
}
#endif /* EAP_SIM_DB */
+ hapd->eap_cfg = authsrv_eap_config(hapd);
+ if (!hapd->eap_cfg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to build EAP server configuration");
+ authsrv_deinit(hapd);
+ return -1;
+ }
+
#ifdef RADIUS_SERVER
if (hapd->conf->radius_server_clients &&
hostapd_setup_radius_srv(hapd))
@@ -302,4 +345,7 @@
hapd->eap_sim_db_priv = NULL;
}
#endif /* EAP_SIM_DB */
+
+ eap_server_config_free(hapd->eap_cfg);
+ hapd->eap_cfg = NULL;
}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index a51b949..331c09b 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -456,7 +456,8 @@
pos = hostapd_eid_ext_supp_rates(hapd, pos);
/* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
+ if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa)))
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
@@ -498,7 +499,8 @@
#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);
@@ -523,7 +525,8 @@
#endif /* CONFIG_IEEE80211AC */
/* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA)
+ if (hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa))
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
@@ -553,7 +556,6 @@
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
- pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
@@ -1164,7 +1166,8 @@
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
/* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
+ if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa)))
tailpos = hostapd_eid_wpa(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
@@ -1240,7 +1243,8 @@
#endif /* CONFIG_IEEE80211AC */
/* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA)
+ if (hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa))
tailpos = hostapd_eid_wpa(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
@@ -1271,7 +1275,6 @@
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
- tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
@@ -1421,11 +1424,19 @@
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
+#ifdef CONFIG_IEEE80211AX
+ params.he_spr = !!hapd->iface->conf->spr.sr_control;
+ params.he_spr_srg_obss_pd_min_offset =
+ hapd->iface->conf->spr.srg_obss_pd_min_offset;
+ params.he_spr_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.srg_obss_pd_max_offset;
+#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
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 @@
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 @@
"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 @@
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 ac23c2b..c4c00fc 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -960,6 +960,8 @@
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,
@@ -1093,11 +1095,18 @@
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
+ /* This is called when the driver indicates that an offloaded DFS has
+ * started CAC. */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ /* TODO: How to check CAC time for ETSI weather channels? */
+ iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
"seg1=%d cac_time=%ds",
- freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
+ iface->dfs_cac_ms / 1000);
iface->cac_started = 1;
+ os_get_reltime(&iface->dfs_cac_start);
return 0;
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 697c3ba..085d423 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -607,47 +607,48 @@
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 @@
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) {
@@ -765,18 +766,10 @@
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
- int netrole_ap = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
- buf = dpp_build_conf_req(auth, json);
+ buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name, 1,
+ hapd->conf->dpp_mud_url, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -922,6 +915,24 @@
}
+static void hostapd_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -945,6 +956,20 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(
+ hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ eloop_register_timeout(
+ 16, 0, hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ return;
+ }
hostapd_drv_send_action_cancel_wait(hapd);
hostapd_dpp_listen_stop(hapd);
if (status == DPP_STATUS_OK)
@@ -957,6 +982,41 @@
NULL);
}
+
+static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+}
+
+
#endif /* CONFIG_DPP2 */
@@ -1403,6 +1463,9 @@
case DPP_PA_CONFIGURATION_RESULT:
hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1506,7 +1569,7 @@
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;
}
@@ -1715,6 +1778,8 @@
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
+ NULL);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3158768..3198bd5 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"
@@ -111,10 +112,8 @@
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -131,6 +130,19 @@
"hostapd_notif_assoc: Skip event with no address");
return -1;
}
+
+ if (is_multicast_ether_addr(addr) ||
+ is_zero_ether_addr(addr) ||
+ os_memcmp(addr, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Do not process any frames with unexpected/invalid SA so that
+ * we do not add any state for unexpected STA addresses or end
+ * up sending out frames to unexpected destination. */
+ wpa_printf(MSG_DEBUG, "%s: Invalid SA=" MACSTR
+ " in received indication - ignore this indication silently",
+ __func__, MAC2STR(addr));
+ return 0;
+ }
+
random_add_randomness(addr, ETH_ALEN);
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@@ -308,6 +320,8 @@
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) {
@@ -324,23 +338,19 @@
} else if (res == WPA_INVALID_AKMP) {
reason = WLAN_REASON_AKMP_NOT_VALID;
status = WLAN_STATUS_AKMP_NOT_VALID;
- }
-#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
+ } else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- }
-#endif /* CONFIG_IEEE80211W */
- else {
+ } else {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
}
goto fail;
}
-#ifdef CONFIG_IEEE80211W
+
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
!sta->sa_query_timed_out &&
@@ -373,7 +383,6 @@
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -390,6 +399,20 @@
}
}
#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;
@@ -1164,12 +1187,10 @@
return;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
return;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index cc75a77..3686438 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -25,7 +28,6 @@
#include "accounting.h"
#include "ap_list.h"
#include "beacon.h"
-#include "iapp.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#include "vlan_init.h"
@@ -296,7 +298,6 @@
ifname, i);
}
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
@@ -308,7 +309,6 @@
}
}
}
-#endif /* CONFIG_IEEE80211W */
}
@@ -360,8 +360,6 @@
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- iapp_deinit(hapd->iapp);
- hapd->iapp = NULL;
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
@@ -1025,6 +1023,43 @@
#define hostapd_das_coa NULL
#endif /* CONFIG_HS20 */
+
+#ifdef CONFIG_SQLITE
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_radius_attributes(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE radius_attributes("
+ " id INTEGER PRIMARY KEY,"
+ " sta TEXT,"
+ " reqtype TEXT,"
+ " attr TEXT"
+ ");"
+ "CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
+
+ wpa_printf(MSG_DEBUG,
+ "Adding database table for RADIUS attribute information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
#endif /* CONFIG_NO_RADIUS */
@@ -1178,6 +1213,24 @@
if (wpa_debug_level <= MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
+
+#ifdef CONFIG_SQLITE
+ if (conf->radius_req_attr_sqlite) {
+ if (sqlite3_open(conf->radius_req_attr_sqlite,
+ &hapd->rad_attr_db)) {
+ wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
+ conf->radius_req_attr_sqlite);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
+ conf->radius_req_attr_sqlite);
+ if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
+ db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SQLITE */
+
hapd->radius = radius_client_init(hapd, conf->radius);
if (hapd->radius == NULL) {
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
@@ -1240,13 +1293,6 @@
return -1;
}
- if (conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
- wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
- "failed.");
- return -1;
- }
-
#ifdef CONFIG_INTERWORKING
if (gas_serv_init(hapd)) {
wpa_printf(MSG_ERROR, "GAS server initialization failed");
@@ -1544,6 +1590,9 @@
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;
@@ -1868,6 +1917,8 @@
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,
@@ -2194,6 +2245,12 @@
hapd->conf ? hapd->conf->iface : "N/A");
hostapd_bss_deinit_no_free(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+#ifdef CONFIG_SQLITE
+ if (hapd->rad_attr_db) {
+ sqlite3_close(hapd->rad_attr_db);
+ hapd->rad_attr_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
hostapd_cleanup(hapd);
}
@@ -2994,10 +3051,6 @@
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
- /* IEEE 802.11F (IAPP) */
- if (hapd->conf->ieee802_11f)
- iapp_new_station(hapd->iapp, sta);
-
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
sta->no_p2p_set = 1;
@@ -3234,7 +3287,8 @@
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/hostapd.h b/src/ap/hostapd.h
index 44ef753..016fe3b 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -9,6 +9,10 @@
#ifndef HOSTAPD_H
#define HOSTAPD_H
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
#include "common/defs.h"
#include "utils/list.h"
#include "ap_config.h"
@@ -175,13 +179,12 @@
u64 acct_session_id;
struct radius_das_data *radius_das;
- struct iapp_data *iapp;
-
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
+ struct eap_config *eap_cfg;
struct rsn_preauth_interface *preauth_iface;
struct os_reltime michael_mic_failure;
@@ -333,12 +336,10 @@
u8 last_gtk[WPA_GTK_MAX_LEN];
size_t last_gtk_len;
-#ifdef CONFIG_IEEE80211W
enum wpa_alg last_igtk_alg;
int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_len;
-#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -390,6 +391,10 @@
#endif /* CONFIG_AIRTIME_POLICY */
u8 last_1x_eapol_key_replay_counter[8];
+
+#ifdef CONFIG_SQLITE
+ sqlite3 *rad_attr_db;
+#endif /* CONFIG_SQLITE */
};
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 532580e..543fa33 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -80,13 +80,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (hapd->conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
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_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_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 @@
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 @@
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 @@
}
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 @@
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 @@
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/iapp.c b/src/ap/iapp.c
deleted file mode 100644
index 2556da3..0000000
--- a/src/ap/iapp.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- *
- * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
- * and IEEE has withdrawn it. In other words, it is likely better to look at
- * using some other mechanism for AP-to-AP communication than extending the
- * implementation here.
- */
-
-/* TODO:
- * Level 1: no administrative or security support
- * (e.g., static BSSID to IP address mapping in each AP)
- * Level 2: support for dynamic mapping of BSSID to IP address
- * Level 3: support for encryption and authentication of IAPP messages
- * - add support for MOVE-notify and MOVE-response (this requires support for
- * finding out IP address for previous AP using RADIUS)
- * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
- * reassociation to another AP
- * - implement counters etc. for IAPP MIB
- * - verify endianness of fields in IAPP messages; are they big-endian as
- * used here?
- * - RADIUS connection for AP registration and BSSID to IP address mapping
- * - TCP connection for IAPP MOVE, CACHE
- * - broadcast ESP for IAPP ADD-notify
- * - ESP for IAPP MOVE messages
- * - security block sending/processing
- * - IEEE 802.11 context transfer
- */
-
-#include "utils/includes.h"
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <netpacket/packet.h>
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "iapp.h"
-
-
-#define IAPP_MULTICAST "224.0.1.178"
-#define IAPP_UDP_PORT 3517
-#define IAPP_TCP_PORT 3517
-
-struct iapp_hdr {
- u8 version;
- u8 command;
- be16 identifier;
- be16 length;
- /* followed by length-6 octets of data */
-} __attribute__ ((packed));
-
-#define IAPP_VERSION 0
-
-enum IAPP_COMMAND {
- IAPP_CMD_ADD_notify = 0,
- IAPP_CMD_MOVE_notify = 1,
- IAPP_CMD_MOVE_response = 2,
- IAPP_CMD_Send_Security_Block = 3,
- IAPP_CMD_ACK_Security_Block = 4,
- IAPP_CMD_CACHE_notify = 5,
- IAPP_CMD_CACHE_response = 6,
-};
-
-
-/* ADD-notify - multicast UDP on the local LAN */
-struct iapp_add_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- be16 seq_num;
-} __attribute__ ((packed));
-
-
-/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
-struct iapp_layer2_update {
- u8 da[ETH_ALEN]; /* broadcast */
- u8 sa[ETH_ALEN]; /* STA addr */
- be16 len; /* 6 */
- u8 dsap; /* null DSAP address */
- u8 ssap; /* null SSAP address, CR=Response */
- u8 control;
- u8 xid_info[3];
-} __attribute__ ((packed));
-
-
-/* MOVE-notify - unicast TCP */
-struct iapp_move_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u16 ctx_block_len;
- /* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-
-/* MOVE-response - unicast TCP */
-struct iapp_move_response {
- u8 addr_len; /* ETH_ALEN */
- u8 status;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u16 ctx_block_len;
- /* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-enum {
- IAPP_MOVE_SUCCESSFUL = 0,
- IAPP_MOVE_DENIED = 1,
- IAPP_MOVE_STALE_MOVE = 2,
-};
-
-
-/* CACHE-notify */
-struct iapp_cache_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u8 current_ap[ETH_ALEN];
- u16 ctx_block_len;
- /* ctx_block_len bytes of context block followed by 16-bit context
- * timeout */
-} __attribute__ ((packed));
-
-
-/* CACHE-response - unicast TCP */
-struct iapp_cache_response {
- u8 addr_len; /* ETH_ALEN */
- u8 status;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
-} __attribute__ ((packed));
-
-enum {
- IAPP_CACHE_SUCCESSFUL = 0,
- IAPP_CACHE_STALE_CACHE = 1,
-};
-
-
-/* Send-Security-Block - unicast TCP */
-struct iapp_send_security_block {
- u8 iv[8];
- u16 sec_block_len;
- /* followed by sec_block_len bytes of security block */
-} __attribute__ ((packed));
-
-
-/* ACK-Security-Block - unicast TCP */
-struct iapp_ack_security_block {
- u8 iv[8];
- u8 new_ap_ack_authenticator[48];
-} __attribute__ ((packed));
-
-
-struct iapp_data {
- struct hostapd_data *hapd;
- u16 identifier; /* next IAPP identifier */
- struct in_addr own, multicast;
- int udp_sock;
- int packet_sock;
-};
-
-
-static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
-{
- char buf[128];
- struct iapp_hdr *hdr;
- struct iapp_add_notify *add;
- struct sockaddr_in addr;
-
- /* Send IAPP ADD-notify to remove possible association from other APs
- */
-
- hdr = (struct iapp_hdr *) buf;
- hdr->version = IAPP_VERSION;
- hdr->command = IAPP_CMD_ADD_notify;
- hdr->identifier = host_to_be16(iapp->identifier++);
- hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
-
- add = (struct iapp_add_notify *) (hdr + 1);
- add->addr_len = ETH_ALEN;
- add->reserved = 0;
- os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
-
- add->seq_num = host_to_be16(seq_num);
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = iapp->multicast.s_addr;
- addr.sin_port = htons(IAPP_UDP_PORT);
- if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0)
- wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
-}
-
-
-static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
-{
- struct iapp_layer2_update msg;
-
- /* Send Level 2 Update Frame to update forwarding tables in layer 2
- * bridge devices */
-
- /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
- * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
-
- os_memset(msg.da, 0xff, ETH_ALEN);
- os_memcpy(msg.sa, addr, ETH_ALEN);
- msg.len = host_to_be16(6);
- msg.dsap = 0; /* NULL DSAP address */
- msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
- msg.control = 0xaf; /* XID response lsb.1111F101.
- * F=0 (no poll command; unsolicited frame) */
- msg.xid_info[0] = 0x81; /* XID format identifier */
- msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
- msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
- * FIX: what is correct RW with 802.11? */
-
- if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
- wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
-}
-
-
-/**
- * iapp_new_station - IAPP processing for a new STA
- * @iapp: IAPP data
- * @sta: The associated station
- */
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
-{
- u16 seq = 0; /* TODO */
-
- if (iapp == NULL)
- return;
-
- /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
- hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
- iapp_send_layer2_update(iapp, sta->addr);
- iapp_send_add(iapp, sta->addr, seq);
-
- /* TODO: If this was reassociation:
- * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
- * Context Block, Timeout)
- * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
- * IP address */
-}
-
-
-static void iapp_process_add_notify(struct iapp_data *iapp,
- struct sockaddr_in *from,
- struct iapp_hdr *hdr, int len)
-{
- struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
- struct sta_info *sta;
-
- if (len != sizeof(*add)) {
- wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
- len, (unsigned long) sizeof(*add));
- return;
- }
-
- sta = ap_get_sta(iapp->hapd, add->mac_addr);
-
- /* IAPP-ADD.indication(MAC Address, Sequence Number) */
- hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_INFO,
- "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
- be_to_host16(add->seq_num),
- inet_ntoa(from->sin_addr), ntohs(from->sin_port),
- sta ? "" : " (STA not found)");
-
- if (!sta)
- return;
-
- /* TODO: could use seq_num to try to determine whether last association
- * to this AP is newer than the one advertised in IAPP-ADD. Although,
- * this is not really a reliable verification. */
-
- hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "Removing STA due to IAPP ADD-notify");
- ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
-}
-
-
-/**
- * iapp_receive_udp - Process IAPP UDP frames
- * @sock: File descriptor for the socket
- * @eloop_ctx: IAPP data (struct iapp_data *)
- * @sock_ctx: Not used
- */
-static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct iapp_data *iapp = eloop_ctx;
- int len, hlen;
- unsigned char buf[128];
- struct sockaddr_in from;
- socklen_t fromlen;
- struct iapp_hdr *hdr;
-
- /* Handle incoming IAPP frames (over UDP/IP) */
-
- fromlen = sizeof(from);
- len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
- (struct sockaddr *) &from, &fromlen);
- if (len < 0) {
- wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
- strerror(errno));
- return;
- }
-
- if (from.sin_addr.s_addr == iapp->own.s_addr)
- return; /* ignore own IAPP messages */
-
- hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "Received %d byte IAPP frame from %s%s\n",
- len, inet_ntoa(from.sin_addr),
- len < (int) sizeof(*hdr) ? " (too short)" : "");
-
- if (len < (int) sizeof(*hdr))
- return;
-
- hdr = (struct iapp_hdr *) buf;
- hlen = be_to_host16(hdr->length);
- hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "RX: version=%d command=%d id=%d len=%d\n",
- hdr->version, hdr->command,
- be_to_host16(hdr->identifier), hlen);
- if (hdr->version != IAPP_VERSION) {
- wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
- hdr->version);
- return;
- }
- if (hlen > len) {
- wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
- hlen, len);
- return;
- }
- if (hlen < len) {
- wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
- len - hlen);
- len = hlen;
- }
-
- switch (hdr->command) {
- case IAPP_CMD_ADD_notify:
- iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
- break;
- case IAPP_CMD_MOVE_notify:
- /* TODO: MOVE is using TCP; so move this to TCP handler once it
- * is implemented.. */
- /* IAPP-MOVE.indication(MAC Address, New BSSID,
- * Sequence Number, AP Address, Context Block) */
- /* TODO: process */
- break;
- default:
- wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
- break;
- }
-}
-
-
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
-{
- struct ifreq ifr;
- struct sockaddr_ll addr;
- int ifindex;
- struct sockaddr_in *paddr, uaddr;
- struct iapp_data *iapp;
- struct ip_mreqn mreq;
- int reuseaddr = 1;
-
- iapp = os_zalloc(sizeof(*iapp));
- if (iapp == NULL)
- return NULL;
- iapp->hapd = hapd;
- iapp->udp_sock = iapp->packet_sock = -1;
-
- /* TODO:
- * open socket for sending and receiving IAPP frames over TCP
- */
-
- iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (iapp->udp_sock < 0) {
- wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
- if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- ifindex = ifr.ifr_ifindex;
-
- if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- paddr = (struct sockaddr_in *) &ifr.ifr_addr;
- if (paddr->sin_family != AF_INET) {
- wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
- paddr->sin_family);
- iapp_deinit(iapp);
- return NULL;
- }
- iapp->own.s_addr = paddr->sin_addr.s_addr;
-
- if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- paddr = (struct sockaddr_in *) &ifr.ifr_addr;
- if (paddr->sin_family != AF_INET) {
- wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
- paddr->sin_family);
- iapp_deinit(iapp);
- return NULL;
- }
- inet_aton(IAPP_MULTICAST, &iapp->multicast);
-
- os_memset(&uaddr, 0, sizeof(uaddr));
- uaddr.sin_family = AF_INET;
- uaddr.sin_port = htons(IAPP_UDP_PORT);
-
- if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
- sizeof(reuseaddr)) < 0) {
- wpa_printf(MSG_INFO,
- "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
- strerror(errno));
- /*
- * Ignore this and try to continue. This is fine for single
- * BSS cases, but may fail if multiple BSSes enable IAPP.
- */
- }
-
- if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
- sizeof(uaddr)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = iapp->multicast;
- mreq.imr_address.s_addr = INADDR_ANY;
- mreq.imr_ifindex = 0;
- if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (iapp->packet_sock < 0) {
- wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sll_family = AF_PACKET;
- addr.sll_ifindex = ifindex;
- if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
- sizeof(addr)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
- iapp, NULL)) {
- wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
- iapp_deinit(iapp);
- return NULL;
- }
-
- wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
-
- /* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
- * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
- * be openned only after receiving Initiate-Accept. If Initiate-Reject
- * is received, IAPP is not started. */
-
- return iapp;
-}
-
-
-void iapp_deinit(struct iapp_data *iapp)
-{
- struct ip_mreqn mreq;
-
- if (iapp == NULL)
- return;
-
- if (iapp->udp_sock >= 0) {
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = iapp->multicast;
- mreq.imr_address.s_addr = INADDR_ANY;
- mreq.imr_ifindex = 0;
- if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
- strerror(errno));
- }
-
- eloop_unregister_read_sock(iapp->udp_sock);
- close(iapp->udp_sock);
- }
- if (iapp->packet_sock >= 0) {
- eloop_unregister_read_sock(iapp->packet_sock);
- close(iapp->packet_sock);
- }
- os_free(iapp);
-}
diff --git a/src/ap/iapp.h b/src/ap/iapp.h
deleted file mode 100644
index c221183..0000000
--- a/src/ap/iapp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef IAPP_H
-#define IAPP_H
-
-struct iapp_data;
-
-#ifdef CONFIG_IAPP
-
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
-void iapp_deinit(struct iapp_data *iapp);
-
-#else /* CONFIG_IAPP */
-
-static inline void iapp_new_station(struct iapp_data *iapp,
- struct sta_info *sta)
-{
-}
-
-static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
- const char *iface)
-{
- return NULL;
-}
-
-static inline void iapp_deinit(struct iapp_data *iapp)
-{
-}
-
-#endif /* CONFIG_IAPP */
-
-#endif /* IAPP_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index fff35b7..4d30bae 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -98,6 +98,8 @@
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 @@
*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 @@
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 @@
*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 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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
*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 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 @@
#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 @@
* 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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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;
@@ -1406,12 +1518,10 @@
return WLAN_STATUS_AKMP_NOT_VALID;
if (res == WPA_ALLOC_FAIL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-#endif /* CONFIG_IEEE80211W */
if (res == WPA_INVALID_MDIE)
return WLAN_STATUS_INVALID_MDIE;
if (res == WPA_INVALID_PMKID)
@@ -1554,6 +1664,8 @@
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)
@@ -2865,7 +2977,7 @@
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;
@@ -3073,12 +3185,13 @@
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);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
!sta->sa_query_timed_out &&
@@ -3105,7 +3218,6 @@
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -3150,6 +3262,17 @@
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
@@ -3243,7 +3366,8 @@
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
- if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_printf(MSG_DEBUG,
"HS 2.0: PMF not negotiated by release %d station "
MACSTR, release, MAC2STR(sta->addr));
@@ -3549,10 +3673,8 @@
ies, ies_len);
#endif /* CONFIG_OWE */
-#ifdef CONFIG_IEEE80211W
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p);
@@ -3560,7 +3682,8 @@
#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) {
@@ -3604,6 +3727,8 @@
}
#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 &&
@@ -4150,7 +4275,6 @@
*/
sta->flags |= WLAN_STA_ASSOC_REQ_OK;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
"SA Query procedure", reassoc ? "re" : "");
@@ -4161,7 +4285,6 @@
* trying to associate.
*/
}
-#endif /* CONFIG_IEEE80211W */
/* Make sure that the previously registered inactivity timer will not
* remove the STA immediately. */
@@ -4386,13 +4509,11 @@
}
-#ifdef CONFIG_IEEE80211W
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
category != WLAN_ACTION_HT;
}
-#endif /* CONFIG_IEEE80211W */
static int handle_action(struct hostapd_data *hapd,
@@ -4426,7 +4547,6 @@
return 0;
}
-#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
robust_action_frame(mgmt->u.action.category)) {
@@ -4436,7 +4556,6 @@
"an MFP STA");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
if (sta) {
u16 fc = le_to_host16(mgmt->frame_control);
@@ -4470,11 +4589,9 @@
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
return 1;
-#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
ieee802_11_sa_query_action(hapd, mgmt, len);
return 1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
case WLAN_ACTION_WNM:
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -4626,6 +4743,18 @@
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
+ if (is_multicast_ether_addr(mgmt->sa) ||
+ is_zero_ether_addr(mgmt->sa) ||
+ os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Do not process any frames with unexpected/invalid SA so that
+ * we do not add any state for unexpected STA addresses or end
+ * up sending out frames to unexpected destination. */
+ wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
+ " in received frame - ignore this frame silently",
+ MAC2STR(mgmt->sa));
+ return 0;
+ }
+
if (stype == WLAN_FC_STYPE_BEACON) {
handle_beacon(hapd, mgmt, len, fi);
return 1;
@@ -4862,9 +4991,7 @@
else
mlme_associate_indication(hapd, sta);
-#ifdef CONFIG_IEEE80211W
sta->sa_query_timed_out = 0;
-#endif /* CONFIG_IEEE80211W */
if (sta->eapol_sm == NULL) {
/*
@@ -5257,8 +5384,10 @@
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (is_multicast_ether_addr(src)) {
- /* Broadcast bit set in SA?! Ignore the frame silently. */
+ if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
+ os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
+ * silently. */
return;
}
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 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 a51f3fc..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"
@@ -44,6 +45,41 @@
}
+static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info)
+{
+ u8 sz = 4;
+
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
+ sz += 4;
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ sz += 4;
+
+ return sz;
+}
+
+
+static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
+{
+ struct ieee80211_he_capabilities *cap;
+ size_t cap_len;
+
+ cap = (struct ieee80211_he_capabilities *) buf;
+ cap_len = sizeof(*cap) - sizeof(cap->optional);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
+
+ return len != cap_len;
+}
+
+
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode)
{
@@ -51,12 +87,12 @@
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
u8 *pos = eid;
- u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
+ u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0;
if (!mode)
return eid;
- ie_size = sizeof(struct ieee80211_he_capabilities);
+ ie_size = sizeof(*cap) - sizeof(cap->optional);
ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
mode->he_capab[opmode].phy_cap);
@@ -74,7 +110,6 @@
case CHANWIDTH_USE_HT:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
- mcs_nss_size += 4;
break;
}
@@ -136,6 +171,9 @@
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;
@@ -164,9 +202,26 @@
/* TODO: conditional MaxBSSID Indicator subfield */
- oper->he_oper_params = host_to_le32(params);
+ pos += 6; /* skip the fixed part */
- pos += oper_size;
+ 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;
+
+ 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;
}
@@ -325,6 +380,7 @@
{
if (!he_capab || !hapd->iconf->ieee80211ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
+ ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
sta->flags &= ~WLAN_STA_HE;
os_free(sta->he_capab);
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 *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 @@
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 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 707381f..0b828e9 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -19,8 +19,6 @@
#include "ieee802_11.h"
-#ifdef CONFIG_IEEE80211W
-
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
@@ -304,8 +302,6 @@
ap_sta_stop_sa_query(hapd, sta);
}
-#endif /* CONFIG_IEEE80211W */
-
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
{
@@ -404,14 +400,22 @@
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 &&
@@ -1000,3 +1004,22 @@
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 @@
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 @@
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/ieee802_1x.c b/src/ap/ieee802_1x.c
index d628641..d081031 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -55,10 +58,9 @@
len = sizeof(*xhdr) + datalen;
buf = os_zalloc(len);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "malloc() failed for "
- "ieee802_1x_send(len=%lu)",
- (unsigned long) len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)",
+ __func__, (unsigned long) len);
return;
}
@@ -149,12 +151,12 @@
size_t len, ekey_len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
len = sizeof(*key) + key_len;
buf = os_zalloc(sizeof(*hdr) + len);
- if (buf == NULL)
+ if (!buf)
return;
hdr = (struct ieee802_1x_hdr *) buf;
@@ -195,16 +197,16 @@
/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
* MSK[32..63] is used to sign the message. */
- if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
- wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
- "and signing EAPOL-Key");
+ if (!sm->eap_if->eapKeyData || sm->eap_if->eapKeyDataLen < 64) {
+ wpa_printf(MSG_ERROR,
+ "No eapKeyData available for encrypting and signing EAPOL-Key");
os_free(buf);
return;
}
os_memcpy((u8 *) (key + 1), key_data, key_len);
ekey_len = sizeof(key->key_iv) + 32;
ekey = os_malloc(ekey_len);
- if (ekey == NULL) {
+ if (!ekey) {
wpa_printf(MSG_ERROR, "Could not encrypt key");
os_free(buf);
return;
@@ -241,7 +243,7 @@
struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || !sm->eap_if->eapKeyData)
+ if (!sm || !sm->eap_if->eapKeyData)
return;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
@@ -262,12 +264,13 @@
if (hapd->conf->individual_wep_key_len > 0) {
u8 *ikey;
+
ikey = os_malloc(hapd->conf->individual_wep_key_len);
- if (ikey == NULL ||
+ if (!ikey ||
random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
{
- wpa_printf(MSG_ERROR, "Could not generate random "
- "individual WEP key.");
+ wpa_printf(MSG_ERROR,
+ "Could not generate random individual WEP key");
os_free(ikey);
return;
}
@@ -283,8 +286,8 @@
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
sta->addr, 0, 1, NULL, 0, ikey,
hapd->conf->individual_wep_key_len)) {
- wpa_printf(MSG_ERROR, "Could not set individual WEP "
- "encryption.");
+ wpa_printf(MSG_ERROR,
+ "Could not set individual WEP encryption");
}
os_free(ikey);
@@ -344,13 +347,13 @@
eap_erp_update_identity(sm->eap, eap, len);
identity = eap_get_identity(sm->eap, &identity_len);
- if (identity == NULL)
+ if (!identity)
return;
/* Save station identity for future RADIUS packets */
os_free(sm->identity);
sm->identity = (u8 *) dup_binstr(identity, identity_len);
- if (sm->identity == NULL) {
+ if (!sm->identity) {
sm->identity_len = 0;
return;
}
@@ -405,7 +408,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
hapd->conf->group_mgmt_cipher);
@@ -418,7 +420,6 @@
return -1;
}
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -605,8 +606,7 @@
if (!radius_msg_add_attr(msg, attr->type,
wpabuf_head(attr->val),
wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
return -1;
}
}
@@ -615,6 +615,63 @@
}
+int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
+ struct radius_msg *msg, int acct)
+{
+#ifdef CONFIG_SQLITE
+ const char *attrtxt;
+ char addrtxt[3 * ETH_ALEN];
+ char *sql;
+ sqlite3_stmt *stmt = NULL;
+
+ if (!hapd->rad_attr_db)
+ return 0;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
+
+ sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
+ if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
+ NULL) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
+ sqlite3_errmsg(hapd->rad_attr_db));
+ return -1;
+ }
+ sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ struct hostapd_radius_attr *attr;
+ struct radius_attr_hdr *hdr;
+
+ attrtxt = (const char *) sqlite3_column_text(stmt, 0);
+ attr = hostapd_parse_radius_attr(attrtxt);
+ if (!attr) {
+ wpa_printf(MSG_ERROR,
+ "Skipping invalid attribute from SQL: %s",
+ attrtxt);
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
+ attrtxt);
+ hdr = radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val));
+ hostapd_config_free_radius_attr(attr);
+ if (!hdr) {
+ wpa_printf(MSG_ERROR,
+ "Could not add RADIUS attribute from SQL");
+ continue;
+ }
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+#endif /* CONFIG_SQLITE */
+
+ return 0;
+}
+
+
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len)
@@ -622,18 +679,17 @@
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
ieee802_1x_learn_identity(hapd, sm, eap, len);
- wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
- "packet");
+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS packet");
sm->radius_identifier = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
sm->radius_identifier);
- if (msg == NULL) {
+ if (!msg) {
wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return;
}
@@ -654,6 +710,9 @@
msg) < 0)
goto fail;
+ if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
+ goto fail;
+
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
@@ -677,12 +736,12 @@
int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
+ wpa_printf(MSG_INFO,
+ "Could not copy State attribute from previous Access-Challenge");
goto fail;
}
- if (res > 0) {
+ if (res > 0)
wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
- }
}
if (hapd->conf->radius_request_cui) {
@@ -711,8 +770,8 @@
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP "
- "version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 AP version");
goto fail;
}
@@ -720,6 +779,7 @@
const u8 *pos;
u8 buf[3];
u16 id;
+
pos = wpabuf_head_u8(sta->hs20_ie);
buf[0] = (*pos) >> 4;
if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
@@ -732,8 +792,8 @@
msg,
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
buf, sizeof(buf))) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 "
- "STA version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 STA version");
goto fail;
}
}
@@ -792,13 +852,14 @@
{
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
data = (u8 *) (eap + 1);
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -826,12 +887,11 @@
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO,
- "handle_eap_initiate: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -839,8 +899,8 @@
type = data[0];
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
- "id=%d len=%d) from STA: EAP Initiate type %u",
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAP packet (code=%d id=%d len=%d) from STA: EAP Initiate type %u",
eap->code, eap->identifier, be_to_host16(eap->length),
type);
@@ -851,6 +911,29 @@
}
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_code_str(u8 code)
+{
+ switch (code) {
+ case EAP_CODE_REQUEST:
+ return "request";
+ case EAP_CODE_RESPONSE:
+ return "response";
+ case EAP_CODE_SUCCESS:
+ return "success";
+ case EAP_CODE_FAILURE:
+ return "failure";
+ case EAP_CODE_INITIATE:
+ return "initiate";
+ case EAP_CODE_FINISH:
+ return "finish";
+ default:
+ return "unknown";
+ }
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
@@ -866,44 +949,29 @@
eap = (struct eap_hdr *) buf;
eap_len = be_to_host16(eap->length);
- wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
- eap->code, eap->identifier, eap_len);
+ wpa_printf(MSG_DEBUG, "EAP: code=%d (%s) identifier=%d length=%d",
+ eap->code, eap_code_str(eap->code), eap->identifier,
+ eap_len);
if (eap_len < sizeof(*eap)) {
wpa_printf(MSG_DEBUG, " Invalid EAP length");
return;
} else if (eap_len > len) {
- wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP "
- "packet");
+ wpa_printf(MSG_DEBUG,
+ " Too short frame to contain this EAP packet");
return;
} else if (eap_len < len) {
- wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP "
- "packet", (unsigned long) len - eap_len);
+ wpa_printf(MSG_DEBUG,
+ " Ignoring %lu extra bytes after EAP packet",
+ (unsigned long) len - eap_len);
}
switch (eap->code) {
- case EAP_CODE_REQUEST:
- wpa_printf(MSG_DEBUG, " (request)");
- return;
case EAP_CODE_RESPONSE:
- wpa_printf(MSG_DEBUG, " (response)");
handle_eap_response(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_SUCCESS:
- wpa_printf(MSG_DEBUG, " (success)");
- return;
- case EAP_CODE_FAILURE:
- wpa_printf(MSG_DEBUG, " (failure)");
- return;
case EAP_CODE_INITIATE:
- wpa_printf(MSG_DEBUG, " (initiate)");
handle_eap_initiate(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_FINISH:
- wpa_printf(MSG_DEBUG, " (finish)");
- break;
- default:
- wpa_printf(MSG_DEBUG, " (unknown code)");
- return;
}
}
@@ -912,6 +980,7 @@
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
{
int flags = 0;
+
if (sta->flags & WLAN_STA_PREAUTH)
flags |= EAPOL_SM_PREAUTH;
if (sta->wpa_sm) {
@@ -976,8 +1045,8 @@
sta = ap_get_sta(hapd, sa);
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
- "associated/Pre-authenticating STA");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X data frame from not associated/Pre-authenticating STA");
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
@@ -999,14 +1068,15 @@
hdr->version, hdr->type, datalen);
if (len - sizeof(*hdr) < datalen) {
- wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet");
+ wpa_printf(MSG_INFO,
+ " frame too short for this IEEE 802.1X packet");
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
return;
}
if (len - sizeof(*hdr) > datalen) {
- wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after "
- "IEEE 802.1X packet",
+ wpa_printf(MSG_DEBUG,
+ " ignoring %lu extra octets after IEEE 802.1X packet",
(unsigned long) len - sizeof(*hdr) - datalen);
}
@@ -1027,8 +1097,8 @@
if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "802.1X not enabled and WPS not used");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used");
return;
}
@@ -1036,8 +1106,8 @@
if (key_mgmt != -1 &&
(wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
key_mgmt == WPA_KEY_MGMT_DPP)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "STA is using PSK");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - STA is using PSK");
return;
}
@@ -1060,9 +1130,8 @@
* skipped if the STA is known to support WPS
* 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start "
- "EAPOL until EAPOL-Start is "
- "received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
}
@@ -1085,15 +1154,14 @@
case IEEE802_1X_TYPE_EAPOL_START:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Start from STA");
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
- HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
- "available - ignore it since "
- "STA sent EAPOL-Start");
+ HOSTAPD_LEVEL_DEBUG,
+ "cached PMKSA available - ignore it since STA sent EAPOL-Start");
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
}
sta->eapol_sm->eapolStart = TRUE;
@@ -1104,8 +1172,8 @@
case IEEE802_1X_TYPE_EAPOL_LOGOFF:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Logoff from STA");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
accounting_sta_stop(hapd, sta);
@@ -1117,8 +1185,8 @@
case IEEE802_1X_TYPE_EAPOL_KEY:
wpa_printf(MSG_DEBUG, " EAPOL-Key");
if (!ap_sta_is_authorized(sta)) {
- wpa_printf(MSG_DEBUG, " Dropped key data from "
- "unauthorized Supplicant");
+ wpa_printf(MSG_DEBUG,
+ " Dropped key data from unauthorized Supplicant");
break;
}
break;
@@ -1174,8 +1242,8 @@
#endif /* CONFIG_WPS */
if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
- "802.1X not enabled or forced for WPS");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
@@ -1197,11 +1265,11 @@
return;
}
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "start authentication");
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
@@ -1220,8 +1288,8 @@
* initiates the handshake with EAPOL-Start. Only allow the
* wait to be skipped if the STA is known to support WPS 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
- "EAPOL-Start is received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
@@ -1317,7 +1385,7 @@
sta->pending_eapol_rx = NULL;
}
- if (sm == NULL)
+ if (!sm)
return;
sta->eapol_sm = NULL;
@@ -1342,7 +1410,7 @@
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || sm->last_recv_radius == NULL) {
+ if (!sm || !sm->last_recv_radius) {
if (sm)
sm->eap_if->aaaEapNoReq = TRUE;
return;
@@ -1351,21 +1419,21 @@
msg = sm->last_recv_radius;
eap = radius_msg_get_eap(msg);
- if (eap == NULL) {
+ if (!eap) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "could not extract "
- "EAP-Message from RADIUS message");
+ HOSTAPD_LEVEL_WARNING,
+ "could not extract EAP-Message from RADIUS message");
sm->eap_if->aaaEapNoReq = TRUE;
return;
}
if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "too short EAP packet "
- "received from authentication server");
+ HOSTAPD_LEVEL_WARNING,
+ "too short EAP packet received from authentication server");
wpabuf_free(eap);
sm->eap_if->aaaEapNoReq = TRUE;
return;
@@ -1398,8 +1466,8 @@
}
buf[sizeof(buf) - 1] = '\0';
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
- "id=%d len=%d) from RADIUS server: %s",
+ HOSTAPD_LEVEL_DEBUG,
+ "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
hdr->code, hdr->identifier, be_to_host16(hdr->length),
buf);
sm->eap_if->aaaEapReq = TRUE;
@@ -1419,7 +1487,8 @@
u8 *buf;
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
@@ -1482,8 +1551,7 @@
struct radius_attr_data *nclass;
size_t nclass_count;
- if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
- sm == NULL)
+ if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
return;
radius_free_class(&sm->radius_class);
@@ -1492,7 +1560,7 @@
return;
nclass = os_calloc(count, sizeof(struct radius_attr_data));
- if (nclass == NULL)
+ if (!nclass)
return;
nclass_count = 0;
@@ -1509,7 +1577,7 @@
} while (class_len < 1);
nclass[nclass_count].data = os_memdup(attr_class, class_len);
- if (nclass[nclass_count].data == NULL)
+ if (!nclass[nclass_count].data)
break;
nclass[nclass_count].len = class_len;
@@ -1518,8 +1586,9 @@
sm->radius_class.attr = nclass;
sm->radius_class.count = nclass_count;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
- "attributes for " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+ MACSTR,
(unsigned long) sm->radius_class.count,
MAC2STR(sta->addr));
}
@@ -1534,7 +1603,7 @@
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
@@ -1542,12 +1611,12 @@
return;
identity = (u8 *) dup_binstr(buf, len);
- if (identity == NULL)
+ if (!identity)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
- "User-Name from Access-Accept '%s'",
+ HOSTAPD_LEVEL_DEBUG,
+ "old identity '%s' updated with User-Name from Access-Accept '%s'",
sm->identity ? (char *) sm->identity : "N/A",
(char *) identity);
@@ -1567,7 +1636,7 @@
u8 *buf;
size_t len;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -1575,7 +1644,7 @@
return;
cui = wpabuf_alloc_copy(buf, len);
- if (cui == NULL)
+ if (!cui)
return;
wpabuf_free(sm->radius_cui);
@@ -1596,14 +1665,16 @@
sta->remediation_method = pos[0];
os_memcpy(sta->remediation_url, pos + 1, len - 1);
sta->remediation_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR " - server method %u URL %s",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR " - server method %u URL %s",
MAC2STR(sta->addr), sta->remediation_method,
sta->remediation_url);
} else {
sta->remediation_url = NULL;
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR, MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR, MAC2STR(sta->addr));
}
/* TODO: assign the STA into remediation VLAN or add filtering */
}
@@ -1616,8 +1687,8 @@
if (len < 3)
return; /* Malformed information */
sta->hs20_deauth_requested = 1;
- wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u "
- "Re-auth Delay %u",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u",
*pos, WPA_GET_LE16(pos + 1));
wpabuf_free(sta->hs20_deauth_req);
sta->hs20_deauth_req = wpabuf_alloc(len + 1);
@@ -1641,16 +1712,17 @@
return; /* Malformed information */
os_free(sta->hs20_session_info_url);
sta->hs20_session_info_url = os_malloc(len);
- if (sta->hs20_session_info_url == NULL)
+ if (!sta->hs20_session_info_url)
return;
swt = pos[0];
os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
sta->hs20_session_info_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
- "(session_timeout=%d)",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Session Information URL='%s' SWT=%u (session_timeout=%d)",
sta->hs20_session_info_url, swt, session_timeout);
if (session_timeout < 0) {
- wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: No Session-Timeout set - ignore session info URL");
return;
}
if (swt == 255)
@@ -1783,6 +1855,7 @@
ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
{
struct sta_id_search id_search;
+
id_search.identifier = identifier;
id_search.sm = NULL;
ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
@@ -1853,9 +1926,9 @@
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
- if (sm == NULL) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
- "station for this RADIUS message");
+ if (!sm) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Could not find matching station for this RADIUS message");
return RADIUS_RX_UNKNOWN;
}
sta = sm->sta;
@@ -1866,12 +1939,12 @@
radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
0) < 0 &&
radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
- "Message-Authenticator since it does not include "
- "EAP-Message");
+ wpa_printf(MSG_DEBUG,
+ "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
- wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@@ -1904,8 +1977,7 @@
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
- "ignored too small "
- "Acct-Interim-Interval %d",
+ "ignored too small Acct-Interim-Interval %d",
acct_interim_interval);
} else
sta->acct_interim_interval = acct_interim_interval;
@@ -1974,8 +2046,7 @@
hostapd_logger(hapd, sm->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
- "using EAP timeout of %d seconds (from "
- "RADIUS)",
+ "using EAP timeout of %d seconds (from RADIUS)",
sm->eap_if->aaaMethodTimeout);
} else {
/*
@@ -2014,7 +2085,8 @@
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -2050,7 +2122,7 @@
os_free(eapol->default_wep_key);
eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
- if (eapol->default_wep_key == NULL ||
+ if (!eapol->default_wep_key ||
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
wpa_printf(MSG_INFO, "Could not generate random WEP key");
@@ -2094,8 +2166,8 @@
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to generate a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to generate a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2109,8 +2181,8 @@
eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to configure a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to configure a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2145,8 +2217,8 @@
(identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR,
WSC_ID_REGISTRAR_LEN) == 0))) {
- wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
- "WLAN_STA_WPS");
+ wpa_printf(MSG_DEBUG,
+ "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS");
sta->flags |= WLAN_STA_WPS;
}
}
@@ -2173,6 +2245,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
if (preauth)
rsn_preauth_finished(hapd, sta, success);
else
@@ -2190,7 +2263,7 @@
int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
- if (eap_user == NULL)
+ if (!eap_user)
goto out;
os_memset(user, 0, sizeof(*user));
@@ -2203,7 +2276,7 @@
if (eap_user->password) {
user->password = os_memdup(eap_user->password,
eap_user->password_len);
- if (user->password == NULL)
+ if (!user->password)
goto out;
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
@@ -2233,8 +2306,9 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+
sta = ap_get_sta(hapd, addr);
- if (sta == NULL || sta->eapol_sm == NULL)
+ if (!sta || !sta->eapol_sm)
return 0;
return 1;
}
@@ -2271,6 +2345,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_set_sta_authorized(hapd, sta, authorized);
}
@@ -2279,6 +2354,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_abort_auth(hapd, sta);
}
@@ -2289,6 +2365,7 @@
#ifndef CONFIG_NO_RC4
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_tx_key(hapd, sta);
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
@@ -2300,6 +2377,7 @@
{
/* struct hostapd_data *hapd = ctx; */
struct sta_info *sta = sta_ctx;
+
switch (type) {
case EAPOL_AUTH_SM_CHANGE:
wpa_auth_sm_notify(sta->wpa_sm);
@@ -2349,43 +2427,15 @@
dl_list_init(&hapd->erp_keys);
os_memset(&conf, 0, sizeof(conf));
+ conf.eap_cfg = hapd->eap_cfg;
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa;
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
- conf.eap_server = hapd->conf->eap_server;
- conf.ssl_ctx = hapd->ssl_ctx;
- conf.msg_ctx = hapd->msg_ctx;
- conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
- conf.erp = hapd->conf->eap_server_erp;
- conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
- conf.tls_flags = hapd->conf->tls_flags;
- conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
- conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
- conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
- conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
- conf.eap_fast_prov = hapd->conf->eap_fast_prov;
- conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
- conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
- conf.eap_teap_auth = hapd->conf->eap_teap_auth;
- conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
- conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
- conf.tnc = hapd->conf->tnc;
- conf.wps = hapd->wps;
- conf.fragment_size = hapd->conf->fragment_size;
- conf.pwd_group = hapd->conf->pwd_group;
- conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
- if (hapd->conf->server_id) {
- conf.server_id = (const u8 *) hapd->conf->server_id;
- conf.server_id_len = os_strlen(hapd->conf->server_id);
- } else {
- conf.server_id = (const u8 *) "hostapd";
- conf.server_id_len = 7;
- }
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@@ -2404,7 +2454,7 @@
#endif /* CONFIG_ERP */
hapd->eapol_auth = eapol_auth_init(&conf, &cb);
- if (hapd->eapol_auth == NULL)
+ if (!hapd->eapol_auth)
return -1;
if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
@@ -2425,7 +2475,7 @@
ieee802_1x_rekey(hapd, NULL);
- if (hapd->eapol_auth->default_wep_key == NULL)
+ if (!hapd->eapol_auth->default_wep_key)
return -1;
}
@@ -2468,7 +2518,7 @@
const unsigned char rfc1042_hdr[ETH_ALEN] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
- if (sta == NULL)
+ if (!sta)
return -1;
if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
return 0;
@@ -2497,8 +2547,8 @@
if (len < (int) sizeof(*xhdr))
return 0;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
- "type=%d length=%d - ack=%d",
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " TX status - version=%d type=%d length=%d - ack=%d",
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
@@ -2517,6 +2567,7 @@
if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
const struct wpa_eapol_key *wpa;
+
wpa = (const struct wpa_eapol_key *) pos;
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
wpa->type == EAPOL_KEY_TYPE_WPA)
@@ -2532,8 +2583,8 @@
if (!ack && pos + sizeof(*key) <= buf + len) {
key = (struct ieee802_1x_eapol_key *) pos;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
- "frame (%scast index=%d)",
+ HOSTAPD_LEVEL_DEBUG,
+ "did not Ack EAPOL-Key frame (%scast index=%d)",
key->key_index & BIT(7) ? "uni" : "broad",
key->key_index & ~BIT(7));
/* TODO: re-send EAPOL-Key couple of times (with short delay
@@ -2553,7 +2604,7 @@
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
{
- if (sm == NULL || sm->identity == NULL)
+ if (!sm || !sm->identity)
return NULL;
*len = sm->identity_len;
@@ -2564,7 +2615,7 @@
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx)
{
- if (sm == NULL || sm->radius_class.attr == NULL ||
+ if (!sm || !sm->radius_class.attr ||
idx >= (int) sm->radius_class.count)
return NULL;
@@ -2575,7 +2626,7 @@
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return NULL;
return sm->radius_cui;
}
@@ -2584,7 +2635,7 @@
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
- if (sm == NULL)
+ if (!sm)
return NULL;
*len = sm->eap_if->eapKeyDataLen;
@@ -2609,7 +2660,7 @@
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled)
{
- if (sm == NULL)
+ if (!sm)
return;
sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
eapol_auth_step(sm);
@@ -2619,7 +2670,7 @@
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
int valid)
{
- if (sm == NULL)
+ if (!sm)
return;
sm->portValid = valid ? TRUE : FALSE;
eapol_auth_step(sm);
@@ -2628,7 +2679,7 @@
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
{
- if (sm == NULL)
+ if (!sm)
return;
if (pre_auth)
sm->flags |= EAPOL_SM_PREAUTH;
@@ -2660,7 +2711,7 @@
const char *name2;
char *identity_buf = NULL;
- if (sm == NULL)
+ if (!sm)
return 0;
ret = os_snprintf(buf + len, buflen - len,
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index d771ba5..bb85b93 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -59,6 +59,8 @@
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
+int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
+ struct radius_msg *msg, int acct);
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 51d7884..cbb8752 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -46,9 +46,7 @@
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
-#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
@@ -301,10 +299,8 @@
os_free(sta->challenge);
-#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
@@ -1095,8 +1091,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
@@ -1186,8 +1180,6 @@
sta->sa_query_count = 0;
}
-#endif /* CONFIG_IEEE80211W */
-
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta)
@@ -1414,7 +1406,7 @@
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]" : ""),
@@ -1433,6 +1425,7 @@
(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/sta_info.h b/src/ap/sta_info.h
index 5456a63..de806b4 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -171,7 +171,6 @@
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
-#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
@@ -179,7 +178,6 @@
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_reltime sa_query_start;
-#endif /* CONFIG_IEEE80211W */
#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 27c69d3..e4dcfe9 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -150,7 +150,6 @@
pos += gtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
(int) gtk_elem_len);
-#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@@ -158,7 +157,6 @@
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
-#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e1c0c2c..7b690d7 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -708,6 +708,7 @@
#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);
@@ -1818,10 +1819,8 @@
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
(event == WPA_AUTH || event == WPA_ASSOC))
@@ -2938,6 +2937,22 @@
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;
@@ -3045,8 +3060,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
if (sm->mgmt_frame_prot) {
@@ -3093,21 +3106,6 @@
return pos;
}
-#else /* CONFIG_IEEE80211W */
-
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
-{
- return 0;
-}
-
-
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
-{
- return pos;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
static int ocv_oci_len(struct wpa_state_machine *sm)
{
@@ -3145,7 +3143,7 @@
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
sm->TimeoutEvt = FALSE;
@@ -3196,7 +3194,7 @@
return;
gtk = dummy_gtk;
}
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -3204,7 +3202,6 @@
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -3261,7 +3258,7 @@
#endif /* CONFIG_IEEE80211R_AP */
if (gtk) {
u8 hdr[2];
- hdr[0] = keyidx & 0x03;
+ hdr[0] = gtkidx & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
@@ -3333,7 +3330,7 @@
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
}
@@ -3746,7 +3743,6 @@
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
size_t len;
len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
@@ -3759,7 +3755,6 @@
wpa_hexdump_key(MSG_DEBUG, "IGTK",
group->IGTK[group->GN_igtk - 4], len);
}
-#endif /* CONFIG_IEEE80211W */
return ret;
}
@@ -3777,10 +3772,8 @@
os_memset(group->GTK, 0, sizeof(group->GTK));
group->GN = 1;
group->GM = 2;
-#ifdef CONFIG_IEEE80211W
group->GN_igtk = 4;
group->GM_igtk = 5;
-#endif /* CONFIG_IEEE80211W */
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -3869,7 +3862,6 @@
}
-#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_group *gsm = sm->group;
@@ -3898,7 +3890,7 @@
return pos - start;
}
-#endif /* CONFIG_IEEE80211W */
+
#endif /* CONFIG_WNM_AP */
@@ -3915,11 +3907,9 @@
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
@@ -3948,7 +3938,6 @@
group->GTK[group->GN - 1], group->GTK_len) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
enum wpa_alg alg;
size_t len;
@@ -3962,7 +3951,6 @@
group->IGTK[group->GN_igtk - 4], len) < 0)
ret = -1;
}
-#endif /* CONFIG_IEEE80211W */
return ret;
}
@@ -4100,11 +4088,9 @@
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
@@ -4250,8 +4236,12 @@
/* Private MIB */
ret = os_snprintf(buf + len, buflen - len,
+ "wpa=%d\n"
+ "AKMSuiteSelector=" RSN_SUITE "\n"
"hostapdWPAPTKState=%d\n"
"hostapdWPAPTKGroupState=%d\n",
+ sm->wpa,
+ RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
sm->wpa_ptk_state,
sm->wpa_ptk_group_state);
if (os_snprintf_error(buflen - len, ret))
@@ -4975,13 +4965,11 @@
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
GTK[GN], IGTK, [FTIE], [TIE * 2])
@@ -5008,7 +4996,7 @@
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -5016,7 +5004,6 @@
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -5069,12 +5056,11 @@
#endif /* CONFIG_IEEE80211R_AP */
if (gtk) {
u8 hdr[2];
- hdr[0] = keyidx & 0x03;
+ hdr[0] = gtkidx & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
-#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
@@ -5082,7 +5068,6 @@
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
-#endif /* CONFIG_IEEE80211W */
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde);
return -1;
@@ -5139,7 +5124,7 @@
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
return 0;
}
@@ -5153,9 +5138,7 @@
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t kde_len;
u8 *gtk;
@@ -5178,7 +5161,6 @@
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
-#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
if (pos - opos >=
@@ -5187,7 +5169,6 @@
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
-#endif /* CONFIG_IEEE80211W */
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde_buf);
return -1;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index a348bc2..f627838 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -187,11 +187,9 @@
int disable_pmksa_caching;
int okc;
int tx_status;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
int sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -232,6 +230,7 @@
unsigned int fils_cache_id_set:1;
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
+ int sae_pwe;
};
typedef enum {
@@ -320,6 +319,7 @@
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 696f8d5..a599be2 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2232,7 +2232,6 @@
}
-#ifdef CONFIG_IEEE80211W
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
@@ -2279,7 +2278,6 @@
*len = subelem_len;
return subelem;
}
-#endif /* CONFIG_IEEE80211W */
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
@@ -2420,6 +2418,8 @@
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;
@@ -2487,7 +2487,6 @@
r0kh_id_len = sm->r0kh_id_len;
anonce = sm->ANonce;
snonce = sm->SNonce;
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot) {
u8 *igtk;
size_t igtk_len;
@@ -2510,7 +2509,6 @@
subelem_len += igtk_len;
os_free(igtk);
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2584,6 +2582,13 @@
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;
@@ -2596,6 +2601,7 @@
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;
@@ -3253,6 +3259,8 @@
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",
@@ -3272,6 +3280,8 @@
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;
@@ -3290,6 +3300,9 @@
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 0800a87..ddab950 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -64,11 +64,9 @@
wconf->ocv = conf->ocv;
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_MAX_LEN)
@@ -107,9 +105,7 @@
wconf->rsn_pairwise = WPA_CIPHER_CCMP;
wconf->rsn_preauth = 0;
wconf->disable_pmksa_caching = 1;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = 1;
-#endif /* CONFIG_IEEE80211W */
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
@@ -134,6 +130,7 @@
os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
+ wconf->sae_pwe = conf->sae_pwe;
}
@@ -380,7 +377,6 @@
os_memcpy(sta->last_tk, key, key_len);
sta->last_tk_len = key_len;
}
-#ifdef CONFIG_IEEE80211W
} else if (alg == WPA_ALG_IGTK ||
alg == WPA_ALG_BIP_GMAC_128 ||
alg == WPA_ALG_BIP_GMAC_256 ||
@@ -390,7 +386,6 @@
if (key)
os_memcpy(hapd->last_igtk, key, key_len);
hapd->last_igtk_len = key_len;
-#endif /* CONFIG_IEEE80211W */
} else {
hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx;
@@ -896,18 +891,28 @@
{
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 4babd0c..a993f50 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -102,6 +102,8 @@
u8 *wpa_ie;
size_t wpa_ie_len;
+ u8 *rsnxe;
+ size_t rsnxe_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@@ -190,10 +192,8 @@
Boolean changed;
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
-#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
-#endif /* CONFIG_IEEE80211W */
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -269,6 +269,7 @@
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 2e5c916..2e6d059 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -183,7 +183,6 @@
num_suites++;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
@@ -194,7 +193,6 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -286,13 +284,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -314,7 +310,6 @@
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (2 + 4 > buf + len - pos)
@@ -347,7 +342,6 @@
}
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -378,6 +372,26 @@
}
+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;
@@ -411,13 +425,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -464,6 +476,11 @@
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)) {
@@ -532,6 +549,7 @@
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)
{
@@ -607,12 +625,10 @@
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
selector = RSN_AUTH_KEY_MGMT_SAE;
@@ -717,12 +733,10 @@
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (key_mgmt & WPA_KEY_MGMT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
@@ -758,7 +772,6 @@
return WPA_INVALID_PAIRWISE;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, "Management frame protection "
@@ -807,7 +820,6 @@
"Management frame protection cannot use TKIP");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -941,6 +953,21 @@
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;
}
@@ -975,153 +1002,6 @@
#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;
- }
-
-#ifdef CONFIG_IEEE80211W
- 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;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#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 a38b206..dd44b9e 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -9,41 +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;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
-#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/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 6161cdb..33caeaf 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -358,12 +358,10 @@
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
cred->key_len != 2 * PMK_LEN) {
bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
-#ifdef CONFIG_IEEE80211W
if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
bss->ieee80211w =
MGMT_FRAME_PROTECTION_OPTIONAL;
bss->sae_require_mfp = 1;
-#endif /* CONFIG_IEEE80211W */
}
if (cred->key_len >= 8 && cred->key_len < 64) {
@@ -533,9 +531,7 @@
if (wpa) {
char *prefix;
-#ifdef CONFIG_IEEE80211W
int sae = 0;
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa=%d\n", wpa);
@@ -553,13 +549,10 @@
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
cred->key_len != 2 * PMK_LEN) {
fprintf(nconf, "%sSAE", prefix);
-#ifdef CONFIG_IEEE80211W
sae = 1;
-#endif /* CONFIG_IEEE80211W */
}
fprintf(nconf, "\n");
-#ifdef CONFIG_IEEE80211W
if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
fprintf(nconf, "ieee80211w=%d\n",
MGMT_FRAME_PROTECTION_OPTIONAL);
@@ -567,7 +560,6 @@
}
if (sae)
fprintf(nconf, "sae_require_mfp=1\n");
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa_pairwise=");
prefix = "";
diff --git a/src/common/Makefile b/src/common/Makefile
index e703630..ccb280e 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -9,7 +9,6 @@
include ../lib.rules
CFLAGS += -DCONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
CFLAGS += -DCONFIG_SUITE
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 @@
/* 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 @@
};
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 @@
}
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 @@
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 3eb86c5..ab7072c 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -610,6 +610,91 @@
}
+static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
+ u8 *secret, size_t *secret_len)
+{
+ EVP_PKEY_CTX *ctx;
+ int ret = -1;
+
+ ERR_clear_error();
+ *secret_len = 0;
+
+ ctx = EVP_PKEY_CTX_new(own, NULL);
+ if (!ctx) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (EVP_PKEY_derive_init(ctx) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: EVP_PKEY_derive_set_peet failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ u8 buf[200];
+ int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
+
+ /* It looks like OpenSSL can return unexpectedly large buffer
+ * need for shared secret from EVP_PKEY_derive(NULL) in some
+ * cases. For example, group 19 has shown cases where secret_len
+ * is set to 72 even though the actual length ends up being
+ * updated to 32 when EVP_PKEY_derive() is called with a buffer
+ * for the value. Work around this by trying to fetch the value
+ * and continue if it is within supported range even when the
+ * initial buffer need is claimed to be larger. */
+ wpa_printf(level,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ if (*secret_len > 200)
+ goto fail;
+ if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
+ buf, *secret_len);
+ os_memcpy(secret, buf, *secret_len);
+ forced_memzero(buf, sizeof(buf));
+ goto done;
+ }
+
+ if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ ret = 0;
+
+fail:
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
+
static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
{
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
@@ -657,6 +742,34 @@
}
+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;
@@ -2142,7 +2255,6 @@
{
struct dpp_authentication *auth;
size_t nonce_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
struct wpabuf *pi = NULL;
const u8 *r_pubkey_hash, *i_pubkey_hash;
@@ -2211,21 +2323,10 @@
goto fail;
/* ECDH: M = pI * BR */
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
+ auth->Mx, &secret_len) < 0)
goto fail;
- }
auth->secret_len = secret_len;
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
@@ -2277,7 +2378,6 @@
out:
wpabuf_free(pi);
- EVP_PKEY_CTX_free(ctx);
return auth;
fail:
dpp_auth_deinit(auth);
@@ -2304,7 +2404,7 @@
}
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
json_len = os_strlen(json);
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
@@ -2440,6 +2540,67 @@
}
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name, int netrole_ap,
+ const char *mud_url, int *opclasses)
+{
+ size_t len, nlen;
+ const char *tech = "infra";
+ const char *dpp_name;
+ char *nbuf;
+ struct wpabuf *buf, *json;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+ static const char *bogus_tech = "knfra";
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+ tech = bogus_tech;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ dpp_name = name ? name : "Test";
+ len = os_strlen(dpp_name);
+ nlen = len * 6 + 1;
+ nbuf = os_malloc(nlen);
+ if (!nbuf)
+ return NULL;
+ json_escape_string(nbuf, nlen, dpp_name, len);
+
+ len = 100 + os_strlen(nbuf) + int_array_len(opclasses) * 4;
+ if (mud_url && mud_url[0])
+ len += 10 + os_strlen(mud_url);
+ json = wpabuf_alloc(len);
+ if (!json) {
+ os_free(nbuf);
+ return NULL;
+ }
+
+ wpabuf_printf(json,
+ "{\"name\":\"%s\","
+ "\"wi-fi_tech\":\"%s\","
+ "\"netRole\":\"%s\"",
+ nbuf, tech, netrole_ap ? "ap" : "sta");
+ if (mud_url && mud_url[0])
+ wpabuf_printf(json, ",\"mudurl\":\"%s\"", mud_url);
+ if (opclasses) {
+ int i;
+
+ wpabuf_put_str(json, ",\"bandSupport\":[");
+ for (i = 0; opclasses[i]; i++)
+ wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
+ wpabuf_put_str(json, "]");
+ }
+ wpabuf_put_str(json, "}");
+ os_free(nbuf);
+
+ buf = dpp_build_conf_req(auth, wpabuf_head(json));
+ wpabuf_free(json);
+
+ return buf;
+}
+
+
static void dpp_auth_success(struct dpp_authentication *auth)
{
wpa_printf(MSG_DEBUG,
@@ -2750,7 +2911,6 @@
static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
{
size_t nonce_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
struct wpabuf *msg, *pr = NULL;
u8 r_auth[4 + DPP_MAX_HASH_LEN];
@@ -2813,20 +2973,9 @@
goto fail;
/* ECDH: N = pR * PI */
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+ auth->Nx, &secret_len) < 0)
goto fail;
- }
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
auth->Nx, auth->secret_len);
@@ -3122,22 +3271,9 @@
}
dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
- ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
- dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
+ if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
goto fail;
- }
auth->secret_len = secret_len;
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
@@ -3591,7 +3727,6 @@
const u8 *attr_start, size_t attr_len)
{
EVP_PKEY *pr;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
const u8 *addr[2];
size_t len[2];
@@ -3741,21 +3876,10 @@
}
dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
goto fail;
}
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
EVP_PKEY_free(auth->peer_protocol_key);
auth->peer_protocol_key = pr;
pr = NULL;
@@ -3927,7 +4051,6 @@
bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len);
EVP_PKEY_free(pr);
- EVP_PKEY_CTX_free(ctx);
return NULL;
}
@@ -4265,8 +4388,8 @@
}
-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;
@@ -4277,6 +4400,7 @@
conf_sta = dpp_configuration_alloc(pos + 10);
if (!conf_sta)
goto fail;
+ conf_sta->netrole = DPP_NETROLE_STA;
conf = conf_sta;
}
@@ -4285,6 +4409,7 @@
conf_ap = dpp_configuration_alloc(pos + 9);
if (!conf_ap)
goto fail;
+ conf_ap->netrole = DPP_NETROLE_AP;
conf = conf_ap;
}
@@ -4362,8 +4487,15 @@
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:
@@ -4373,6 +4505,41 @@
}
+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)
{
@@ -4412,6 +4579,18 @@
}
}
+ pos = os_strstr(cmd, " conn_status=");
+ if (pos) {
+ pos += 13;
+ 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");
@@ -4423,18 +4602,26 @@
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);
@@ -4545,8 +4732,21 @@
}
+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;
@@ -4567,6 +4767,7 @@
size_t extra_len = 1000;
int incl_legacy;
enum dpp_akm akm;
+ const char *akm_str;
if (!auth->conf) {
wpa_printf(MSG_INFO,
@@ -4620,7 +4821,8 @@
#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 */
@@ -4719,7 +4921,11 @@
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, ",");
@@ -4760,16 +4966,21 @@
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, "}}");
@@ -4781,29 +4992,37 @@
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);
}
@@ -4811,7 +5030,7 @@
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;
@@ -4819,18 +5038,23 @@
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;
- /* { E-nonce, configurationObject}ke */
+ /* { E-nonce, configurationObject[, sendConnStatus]}ke */
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);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -4878,6 +5102,20 @@
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");
+ wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
+ wpabuf_put_le16(clear, 0);
+ }
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
@@ -4926,6 +5164,7 @@
"DPP: Configuration Response attributes", msg);
out:
wpabuf_free(conf);
+ wpabuf_free(conf2);
wpabuf_free(clear);
return msg;
@@ -5054,6 +5293,26 @@
goto fail;
}
+ token = json_get_member(root, "mudurl");
+ if (token && token->type == JSON_STRING)
+ wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
+
+ token = json_get_member(root, "bandSupport");
+ if (token && token->type == JSON_ARRAY) {
+ wpa_printf(MSG_DEBUG, "DPP: bandSupport");
+ token = token->child;
+ while (token) {
+ if (token->type != JSON_NUMBER)
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid bandSupport array member type");
+ else
+ wpa_printf(MSG_DEBUG,
+ "DPP: Supported global operating class: %d",
+ token->number);
+ token = token->sibling;
+ }
+ }
+
resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
fail:
@@ -5143,7 +5402,7 @@
}
-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;
@@ -5160,28 +5419,28 @@
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;
}
@@ -5349,6 +5608,7 @@
static int dpp_parse_connector(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
const unsigned char *payload,
u16 payload_len)
{
@@ -5476,7 +5736,7 @@
}
-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;
@@ -5484,13 +5744,14 @@
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;
@@ -5684,6 +5945,7 @@
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;
@@ -5695,10 +5957,10 @@
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;
}
@@ -5737,16 +5999,17 @@
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:
@@ -5777,8 +6040,32 @@
}
+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)
@@ -5791,6 +6078,38 @@
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;
}
@@ -5800,6 +6119,7 @@
{
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)
@@ -5838,8 +6158,17 @@
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) {
@@ -5852,13 +6181,13 @@
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",
@@ -5955,17 +6284,32 @@
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,
+ DPP_ATTR_SEND_CONN_STATUS, &status_len);
+ if (status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested connection status result");
+ auth->conn_status_requested = 1;
+ }
+#endif /* CONFIG_DPP2 */
ret = 0;
@@ -5976,6 +6320,7 @@
#ifdef CONFIG_DPP2
+
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
const u8 *hdr,
const u8 *attr_start, size_t attr_len)
@@ -6056,7 +6401,6 @@
bin_clear_free(unwrapped, unwrapped_len);
return ret;
}
-#endif /* CONFIG_DPP2 */
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
@@ -6074,7 +6418,7 @@
clear = wpabuf_alloc(clear_len);
msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
if (!clear || !msg)
- return NULL;
+ goto fail;
/* DPP Status */
dpp_build_attr_status(clear, status);
@@ -6115,6 +6459,219 @@
}
+static int valid_channel_list(const char *val)
+{
+ while (*val) {
+ if (!((*val >= '0' && *val <= '9') ||
+ *val == '/' || *val == ','))
+ return 0;
+ val++;
+ }
+
+ return 1;
+}
+
+
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list)
+{
+ const u8 *wrapped_data, *status, *e_nonce;
+ u16 wrapped_data_len, status_len, e_nonce_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ enum dpp_status_error ret = 256;
+ struct json_token *root = NULL, *token;
+
+ *ssid_len = 0;
+ *channel_list = NULL;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE,
+ &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
+ auth->e_nonce, e_nonce_len);
+ goto fail;
+ }
+
+ status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
+ &status_len);
+ if (!status) {
+ dpp_auth_fail(auth,
+ "Missing required DPP Connection Status attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ status, status_len);
+
+ root = json_parse((const char *) status, status_len);
+ if (!root) {
+ dpp_auth_fail(auth, "Could not parse connStatus");
+ goto fail;
+ }
+
+ token = json_get_member(root, "ssid");
+ if (token && token->type == JSON_STRING &&
+ os_strlen(token->string) <= SSID_MAX_LEN) {
+ *ssid_len = os_strlen(token->string);
+ os_memcpy(ssid, token->string, *ssid_len);
+ }
+
+ token = json_get_member(root, "channelList");
+ if (token && token->type == JSON_STRING &&
+ valid_channel_list(token->string))
+ *channel_list = os_strdup(token->string);
+
+ token = json_get_member(root, "result");
+ if (!token || token->type != JSON_NUMBER) {
+ dpp_auth_fail(auth, "No connStatus - result");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
+ ret = token->number;
+
+fail:
+ json_free(root);
+ bin_clear_free(unwrapped, unwrapped_len);
+ return ret;
+}
+
+
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list)
+{
+ struct wpabuf *msg, *clear, *json;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ json = wpabuf_alloc(1000);
+ if (!json)
+ return NULL;
+ wpabuf_printf(json, "{\"result\":%d", result);
+ if (ssid) {
+ char ssid_str[6 * SSID_MAX_LEN + 1];
+
+ wpabuf_put_str(json, ",\"ssid\":\"");
+ json_escape_string(ssid_str, sizeof(ssid_str),
+ (const char *) ssid, ssid_len);
+ wpabuf_put_str(json, ssid_str);
+ wpabuf_put_str(json, "\"");
+ }
+ if (channel_list)
+ wpabuf_printf(json, ",\"channelList\":\"%s\"", channel_list);
+ wpabuf_put_str(json, "}");
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ wpabuf_head(json), wpabuf_len(json));
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+ /* DPP Connection Status */
+ wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+ wpabuf_put_le16(clear, wpabuf_len(json));
+ wpabuf_put_buf(clear, json);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data (none) */
+ addr[1] = wpabuf_put(msg, 0);
+ len[1] = 0;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
+ msg);
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
void dpp_configurator_free(struct dpp_configurator *conf)
{
if (!conf)
@@ -6240,11 +6797,11 @@
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),
@@ -6427,7 +6984,6 @@
const char *pos, *end;
unsigned char *own_conn = NULL;
size_t own_conn_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t Nx_len;
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
@@ -6541,18 +7097,8 @@
}
/* ECDH: N = nk * PK */
- ctx = EVP_PKEY_CTX_new(own_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
- Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
Nx, Nx_len);
@@ -6575,7 +7121,6 @@
if (ret != DPP_STATUS_OK)
os_memset(intro, 0, sizeof(*intro));
os_memset(Nx, 0, sizeof(Nx));
- EVP_PKEY_CTX_free(ctx);
os_free(own_conn);
os_free(signed_connector);
os_free(info.payload);
@@ -7250,7 +7795,6 @@
u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
size_t Kx_len;
int res;
- EVP_PKEY_CTX *ctx = NULL;
if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
@@ -7417,18 +7961,8 @@
goto fail;
/* K = y * X' */
- ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
- Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
Kx, Kx_len);
@@ -7446,7 +7980,6 @@
pkex->exchange_done = 1;
out:
- EVP_PKEY_CTX_free(ctx);
BN_CTX_free(bnctx);
EC_POINT_free(Qi);
EC_POINT_free(Qr);
@@ -7594,7 +8127,6 @@
const struct dpp_curve_params *curve = pkex->own_bi->curve;
EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
BIGNUM *Nx = NULL, *Ny = NULL;
- EVP_PKEY_CTX *ctx = NULL;
EC_KEY *Y_ec = NULL;
size_t Jx_len, Kx_len;
u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7706,18 +8238,8 @@
if (!pkex->y ||
EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
goto fail;
- ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
- Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
Jx, Jx_len);
@@ -7741,19 +8263,8 @@
wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
/* K = x * Y’ */
- EVP_PKEY_CTX_free(ctx);
- ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
- Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
Kx, Kx_len);
@@ -7783,7 +8294,6 @@
BN_free(Nx);
BN_free(Ny);
EC_KEY_free(Y_ec);
- EVP_PKEY_CTX_free(ctx);
BN_CTX_free(bnctx);
EC_GROUP_free(group);
return msg;
@@ -7911,7 +8421,6 @@
const u8 *buf, size_t buflen)
{
const struct dpp_curve_params *curve = pkex->own_bi->curve;
- EVP_PKEY_CTX *ctx = NULL;
size_t Jx_len, Lx_len;
u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7995,18 +8504,8 @@
pkex->peer_bootstrap_key);
/* ECDH: J' = y * A' */
- ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
- Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
Jx, Jx_len);
@@ -8042,19 +8541,8 @@
wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
/* ECDH: L = b * X' */
- EVP_PKEY_CTX_free(ctx);
- ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
- Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
Lx, Lx_len);
@@ -8080,7 +8568,6 @@
goto fail;
out:
- EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
wpabuf_free(A_pub);
wpabuf_free(B_pub);
@@ -8109,7 +8596,6 @@
u8 v[DPP_MAX_HASH_LEN];
size_t Lx_len;
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
- EVP_PKEY_CTX *ctx = NULL;
struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
#ifdef CONFIG_TESTING_OPTIONS
@@ -8180,18 +8666,8 @@
pkex->peer_bootstrap_key);
/* ECDH: L' = x * B' */
- ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
- Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
Lx, Lx_len);
@@ -8231,7 +8707,6 @@
wpabuf_free(B_pub);
wpabuf_free(X_pub);
wpabuf_free(Y_pub);
- EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
return ret;
fail:
@@ -8767,6 +9242,10 @@
#ifdef CONFIG_DPP2
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+
+
static void dpp_connection_free(struct dpp_connection *conn)
{
if (conn->sock >= 0) {
@@ -8776,6 +9255,8 @@
eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
close(conn->sock);
}
+ eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
wpabuf_free(conn->msg);
wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth);
@@ -8999,23 +9480,9 @@
{
struct dpp_authentication *auth = conn->auth;
struct wpabuf *buf;
- char json[100];
int netrole_ap = 0; /* TODO: make this configurable */
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
- buf = dpp_build_conf_req(auth, json);
+ buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -9030,7 +9497,7 @@
return;
}
wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head(buf) + 1,
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
wpabuf_len(buf) - 1);
wpabuf_free(buf);
@@ -9410,7 +9877,7 @@
if (!conn->msg_out)
return -1;
wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head(conn->auth->resp_msg) + 1,
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
wpabuf_len(conn->auth->resp_msg) - 1);
if (dpp_tcp_send(conn) == 1) {
@@ -9458,7 +9925,7 @@
return -1;
}
wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head(msg) + 1,
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
wpabuf_len(msg) - 1);
wpabuf_free(msg);
@@ -9500,6 +9967,22 @@
}
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ if (!conn->auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_connection_remove(conn);
+}
+
+
static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
const u8 *hdr, const u8 *buf,
size_t len)
@@ -9519,6 +10002,18 @@
}
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(
+ dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ eloop_register_timeout(
+ 16, 0, dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ return 0;
+ }
if (status == DPP_STATUS_OK)
wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
DPP_EVENT_CONF_SENT);
@@ -9529,6 +10024,39 @@
}
+static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return -1;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ return -1; /* to remove the completed connection */
+}
+
+
static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
size_t len)
{
@@ -9576,6 +10104,9 @@
return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
case DPP_PA_CONFIGURATION_RESULT:
return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ return dpp_controller_rx_conn_status_result(conn, msg, pos,
+ end - pos);
default:
/* TODO: missing messages types */
wpa_printf(MSG_DEBUG,
@@ -9692,6 +10223,7 @@
if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
return -1;
+#ifdef CONFIG_DPP2
wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
msg = dpp_build_conf_result(auth, status);
@@ -9704,7 +10236,7 @@
return -1;
}
wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
- wpabuf_put_data(encaps, wpabuf_head(msg) + 1, wpabuf_len(msg) - 1);
+ wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
wpabuf_free(msg);
wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
@@ -9717,6 +10249,9 @@
/* This exchange will be terminated in the TX status handler */
return 0;
+#else /* CONFIG_DPP2 */
+ return -1;
+#endif /* CONFIG_DPP2 */
}
diff --git a/src/common/dpp.h b/src/common/dpp.h
index db640ef..0be26d7 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -35,6 +35,7 @@
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
+ DPP_PA_CONNECTION_STATUS_RESULT = 12,
};
enum dpp_attribute_id {
@@ -64,6 +65,8 @@
DPP_ATTR_CHANNEL = 0x1018,
DPP_ATTR_PROTOCOL_VERSION = 0x1019,
DPP_ATTR_ENVELOPED_DATA = 0x101A,
+ DPP_ATTR_SEND_CONN_STATUS = 0x101B,
+ DPP_ATTR_CONN_STATUS = 0x101C,
};
enum dpp_status_error {
@@ -77,6 +80,7 @@
DPP_STATUS_INVALID_CONNECTOR = 7,
DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
+ DPP_STATUS_NO_AP = 10,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@@ -157,10 +161,16 @@
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;
@@ -174,6 +184,8 @@
int psk_set;
};
+#define DPP_MAX_CONF_OBJ 10
+
struct dpp_authentication {
void *msg_ctx;
u8 peer_version;
@@ -222,22 +234,31 @@
int remove_on_tx_status;
int connect_on_tx_status;
int waiting_conf_result;
+ int waiting_conn_status_result;
int auth_success;
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;
@@ -413,6 +434,9 @@
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
const char *json);
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name, int netrole_ap,
+ const char *mud_url, int *opclasses);
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
@@ -439,12 +463,23 @@
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
enum dpp_status_error status);
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list);
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list);
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len);
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/dragonfly.c b/src/common/dragonfly.c
index e98bce6..547be66 100644
--- a/src/common/dragonfly.c
+++ b/src/common/dragonfly.c
@@ -21,14 +21,35 @@
* purposes: FFC groups whose prime is >= 3072 bits and ECC groups
* defined over a prime field whose prime is >= 256 bits. Furthermore,
* ECC groups defined over a characteristic 2 finite field and ECC
- * groups with a co-factor greater than 1 are not suitable. */
+ * groups with a co-factor greater than 1 are not suitable. Disable
+ * groups that use Brainpool curves as well for now since they leak more
+ * timing information due to the prime not being close to a power of
+ * two. */
return group == 19 || group == 20 || group == 21 ||
- group == 28 || group == 29 || group == 30 ||
(!ecc_only &&
(group == 15 || group == 16 || group == 17 || group == 18));
}
+unsigned int dragonfly_min_pwe_loop_iter(int group)
+{
+ if (group == 22 || group == 23 || group == 24) {
+ /* FFC groups for which pwd-value is likely to be >= p
+ * frequently */
+ return 40;
+ }
+
+ if (group == 1 || group == 2 || group == 5 || group == 14 ||
+ group == 15 || group == 16 || group == 17 || group == 18) {
+ /* FFC groups that have prime that is close to a power of two */
+ return 1;
+ }
+
+ /* Default to 40 (this covers most ECC groups) */
+ return 40;
+}
+
+
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
struct crypto_bignum **qr,
struct crypto_bignum **qnr)
diff --git a/src/common/dragonfly.h b/src/common/dragonfly.h
index e7627ef..ec3dd59 100644
--- a/src/common/dragonfly.h
+++ b/src/common/dragonfly.h
@@ -16,6 +16,7 @@
struct crypto_ec;
int dragonfly_suitable_group(int group, int ecc_only);
+unsigned int dragonfly_min_pwe_loop_iter(int group);
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
struct crypto_bignum **qr,
struct crypto_bignum **qnr);
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 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 @@
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 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 9f57828..c6e6440 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -365,6 +365,10 @@
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;
@@ -873,8 +877,8 @@
return HOSTAPD_MODE_IEEE80211A;
}
- /* 56.16 GHz, channel 1..4 */
- if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+ /* 56.16 GHz, channel 1..6 */
+ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
if (sec_channel || vht)
return NUM_HOSTAPD_MODES;
@@ -884,6 +888,19 @@
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;
}
@@ -993,8 +1010,8 @@
if (chan < 149 || chan > 165)
return -1;
return 5000 + 5 * chan;
- case 34: /* 60 GHz band, channels 1..3 */
- if (chan < 1 || chan > 3)
+ case 34: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1031,8 +1048,8 @@
if (chan < 149 || chan > 169)
return -1;
return 5000 + 5 * chan;
- case 18: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 18: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1075,8 +1092,8 @@
if (chan < 100 || chan > 140)
return -1;
return 5000 + 5 * chan;
- case 59: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 3)
+ case 59: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1163,8 +1180,16 @@
if (chan < 36 || chan > 128)
return -1;
return 5000 + 5 * chan;
- case 180: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ 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;
return 56160 + 2160 * chan;
}
@@ -1494,6 +1519,7 @@
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(SAE_HASH_TO_ELEMENT)
}
return "UNKNOWN";
#undef S2S
@@ -1592,6 +1618,7 @@
{ 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 }
};
@@ -1906,6 +1933,43 @@
}
+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)
{
@@ -2014,3 +2078,75 @@
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 @@
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 @@
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 @@
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 @@
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 b0aa913..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 @@
#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))
@@ -2109,7 +2120,7 @@
u8 he_phy_capab_info[11];
/* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field
* and optional variable length PPE Thresholds field. */
- u8 optional[];
+ u8 optional[37];
} STRUCT_PACKED;
struct ieee80211_he_operation {
@@ -2174,6 +2185,10 @@
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 @@
/* 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 0c607b8..a0a0fb5 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -72,7 +72,7 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
- * hostapd.
+ * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
@@ -170,6 +170,11 @@
* to notify the connected station's status. The attributes for this
* command are defined in enum qca_wlan_vendor_attr_link_properties.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY: This command is used to configure
+ * DFS policy and channel hint for ACS operation. This command uses the
+ * attributes defined in enum qca_wlan_vendor_attr_acs_config and
+ * enum qca_acs_dfs_mode.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
* start the P2P Listen offload function in device and pass the listen
* channel, period, interval, count, device types, and vendor specific
@@ -584,6 +589,26 @@
* 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/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.
+ * This new command is alternative to existing command
+ * 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,
@@ -683,7 +708,8 @@
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
/* 110..114 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
- /* 116..117 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY = 116,
+ /* 117 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
@@ -754,6 +780,10 @@
QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
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 {
@@ -1090,31 +1120,162 @@
QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_attr_acs_offload - Defines attributes to be used with
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: Required (u8).
+ * Used with event to notify the primary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY instead.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: Required (u8).
+ * Used with event to notify the secondary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is still used if either of
+ * the driver or user space application doesn't support 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: Required (u8).
+ * (a) Used with command to configure hw_mode from
+ * enum qca_wlan_vendor_acs_hw_mode for ACS operation.
+ * (b) Also used with event to notify the hw_mode of selected primary channel
+ * in ACS operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT mode.
+ * Disable (flag attribute not present) - HT disabled and
+ * Enable (flag attribute present) - HT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT40 mode.
+ * Disable (flag attribute not present) - HT40 disabled and
+ * Enable (flag attribute present) - HT40 enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for VHT mode.
+ * Disable (flag attribute not present) - VHT disabled and
+ * Enable (flag attribute present) - VHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH: Optional (u16) with command and
+ * mandatory with event.
+ * If specified in command path, ACS operation is configured with the given
+ * channel width (in MHz).
+ * In event path, specifies the channel width of the primary channel selected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure channel list using an array of
+ * channel numbers (u8).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver mandates use of QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST whereas
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 0 center channel number selected in
+ * ACS operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 1 center channel number selected in
+ * ACS operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure the channel list using an array of channel
+ * center frequencies in MHz (u32).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver first parses the frequency list and if it fails to get a frequency
+ * list, parses the channel list specified using
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST (considers only 2 GHz and 5 GHz channels in
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY: Required (u32).
+ * Used with event to notify the primary channel center frequency (MHz) selected
+ * in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY: Required (u32).
+ * Used with event to notify the secondary channel center frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 0 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 1 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL.
+ */
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
- QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
- QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE = 3,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED = 4,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED = 5,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED = 6,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH = 7,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST = 8,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL = 9,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL = 10,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST = 11,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY = 12,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_acs_hw_mode - Defines HW mode to be used with the
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_ACS_MODE_IEEE80211B: 802.11b mode
+ * @QCA_ACS_MODE_IEEE80211G: 802.11g mode
+ * @QCA_ACS_MODE_IEEE80211A: 802.11a mode
+ * @QCA_ACS_MODE_IEEE80211AD: 802.11ad mode
+ * @QCA_ACS_MODE_IEEE80211ANY: all modes
+ * @QCA_ACS_MODE_IEEE80211AX: 802.11ax mode
+ */
enum qca_wlan_vendor_acs_hw_mode {
QCA_ACS_MODE_IEEE80211B,
QCA_ACS_MODE_IEEE80211G,
QCA_ACS_MODE_IEEE80211A,
QCA_ACS_MODE_IEEE80211AD,
QCA_ACS_MODE_IEEE80211ANY,
+ QCA_ACS_MODE_IEEE80211AX,
};
/**
@@ -1146,6 +1307,8 @@
* @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
* managed regulatory.
* @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
+ * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE)
+ * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1158,6 +1321,8 @@
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
QCA_WLAN_VENDOR_FEATURE_TWT = 8,
+ QCA_WLAN_VENDOR_FEATURE_11AX = 9,
+ QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -1850,6 +2015,30 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+ /* Attribute to configure disconnect IEs to the driver.
+ * This carries an array of unsigned 8-bit characters.
+ *
+ * If this is configured, driver shall fill the IEs in disassoc/deauth
+ * frame.
+ * These IEs are expected to be considered only for the next
+ * immediate disconnection (disassoc/deauth frame) originated by
+ * the DUT, irrespective of the entity (user space/driver/firmware)
+ * triggering the disconnection.
+ * The host drivers are not expected to use the IEs set through
+ * this interface for further disconnections after the first immediate
+ * disconnection initiated post the configuration.
+ * If the IEs are also updated through cfg80211 interface (after the
+ * enhancement to cfg80211_disconnect), host driver is expected to
+ * take the union of IEs from both of these interfaces and send in
+ * further disassoc/deauth frames.
+ */
+ QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
+
+ /* 8-bit unsigned value for ELNA bypass.
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -1858,10 +2047,23 @@
/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
+ * Channel number on which Access Point should restart.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY: Optional (u32)
+ * Channel center frequency (MHz) on which the access point should restart.
*/
enum qca_wlan_vendor_attr_sap_config {
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
- /* 1 - reserved for QCA */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL = 1,
+
/* List of frequencies on which AP is expected to operate.
* This is irrespective of ACS configuration. This list is a priority
* based one and is looked for before the AP is created to ensure the
@@ -1869,6 +2071,7 @@
* the system.
*/
QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY = 3,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
@@ -1948,6 +2151,54 @@
};
/**
+ * enum qca_acs_dfs_mode - Defines different types of DFS channel
+ * configurations for ACS operation.
+ *
+ * @QCA_ACS_DFS_MODE_NONE: Refer to invalid DFS mode
+ * @QCA_ACS_DFS_MODE_ENABLE: Consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DISABLE: Do not consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in ACS operation
+ */
+enum qca_acs_dfs_mode {
+ QCA_ACS_DFS_MODE_NONE = 0,
+ QCA_ACS_DFS_MODE_ENABLE = 1,
+ QCA_ACS_DFS_MODE_DISABLE = 2,
+ QCA_ACS_DFS_MODE_DEPRIORITIZE = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_acs_config - Defines Configuration attributes
+ * used by the vendor command QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE: Required (u8)
+ * DFS mode for ACS operation from enum qca_acs_dfs_mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT: Required (u8)
+ * channel number hint for ACS operation, if valid channel is specified then
+ * ACS operation gives priority to this channel.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT: Required (u32).
+ * Channel center frequency (MHz) hint for ACS operation, if a valid center
+ * frequency is specified, ACS operation gives priority to this channel.
+ */
+enum qca_wlan_vendor_attr_acs_config {
+ QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT = 3,
+
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
*/
enum qca_wlan_vendor_attr_get_hw_capability {
@@ -3330,6 +3581,345 @@
QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
};
+/**
+ * enum qca_scan_freq_list_type: Frequency list types
+ *
+ * @QCA_PREFERRED_SCAN_FREQ_LIST: The driver shall use the scan frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a preferred frequency list for roaming.
+ *
+ * @QCA_SPECIFIC_SCAN_FREQ_LIST: The driver shall use the frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a specific frequency list for roaming.
+ */
+enum qca_scan_freq_list_type {
+ QCA_PREFERRED_SCAN_FREQ_LIST = 1,
+ QCA_SPECIFIC_SCAN_FREQ_LIST = 2,
+};
+
+/**
+ * enum qca_vendor_attr_scan_freq_list_scheme: Frequency list scheme
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST: Nested attribute of u32 values
+ * List of frequencies in MHz to be considered for a roam scan.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE: Unsigned 32-bit value.
+ * Type of frequency list scheme being configured/gotten as defined by the
+ * enum qca_scan_freq_list_type.
+ */
+enum qca_vendor_attr_scan_freq_list_scheme {
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST = 1,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE = 2,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX =
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_vendor_roam_triggers: Bitmap of roaming triggers
+ *
+ * @QCA_ROAM_TRIGGER_REASON_PER: Set if the roam has to be triggered based on
+ * a bad packet error rates (PER).
+ * @QCA_ROAM_TRIGGER_REASON_BEACON_MISS: Set if the roam has to be triggered
+ * based on beacon misses from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_POOR_RSSI: Set if the roam has to be triggered
+ * due to poor RSSI of the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BETTER_RSSI: Set if the roam has to be triggered
+ * upon finding a BSSID with a better RSSI than the connected BSSID.
+ * Here the RSSI of the current BSSID need not be poor.
+ * @QCA_ROAM_TRIGGER_REASON_PERIODIC: Set if the roam has to be triggered
+ * by triggering a periodic scan to find a better AP to roam.
+ * @QCA_ROAM_TRIGGER_REASON_DENSE: Set if the roam has to be triggered
+ * when the connected channel environment is too noisy/congested.
+ * @QCA_ROAM_TRIGGER_REASON_BTM: Set if the roam has to be triggered
+ * when BTM Request frame is received from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
+ * when the channel utilization is goes above the configured threshold.
+ *
+ * Set the corresponding roam trigger reason bit to consider it for roam
+ * trigger.
+ * Userspace can set multiple bits and send to the driver. The driver shall
+ * consider all of them to trigger/initiate a roam scan.
+ */
+enum qca_vendor_roam_triggers {
+ QCA_ROAM_TRIGGER_REASON_PER = 1 << 0,
+ QCA_ROAM_TRIGGER_REASON_BEACON_MISS = 1 << 1,
+ QCA_ROAM_TRIGGER_REASON_POOR_RSSI = 1 << 2,
+ QCA_ROAM_TRIGGER_REASON_BETTER_RSSI = 1 << 3,
+ QCA_ROAM_TRIGGER_REASON_PERIODIC = 1 << 4,
+ QCA_ROAM_TRIGGER_REASON_DENSE = 1 << 5,
+ QCA_ROAM_TRIGGER_REASON_BTM = 1 << 6,
+ QCA_ROAM_TRIGGER_REASON_BSS_LOAD = 1 << 7,
+};
+
+/**
+ * enum qca_vendor_attr_roam_candidate_selection_criteria:
+ *
+ * Each attribute carries a weightage in percentage (%).
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI: Unsigned 8-bit value.
+ * Represents the weightage to be given for the RSSI selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE: Unsigned 8-bit value.
+ * Represents the weightage to be given for the rate selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band width selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS: Unsigned 8-bit value.
+ * Represents the weightage to be given for the NSS selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION: Unsigned 8-bit value.
+ * Represents the weightage to be given for the channel congestion
+ * selection criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING: Unsigned 8-bit value.
+ * Represents the weightage to be given for the beamforming selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN: Unsigned 8-bit value.
+ * Represents the weightage to be given for the OCE selection
+ * criteria among other parameters.
+ */
+enum qca_vendor_attr_roam_candidate_selection_criteria {
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI = 1,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE = 2,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW = 3,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND = 4,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS = 5,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION = 6,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING = 7,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_MAX =
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
+ * The following attributes are used to set/get/clear the respective
+ * configurations to/from the driver.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable values to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_ENABLE: Unsigned 8-bit value.
+ * Signifies to enable/disable roam control in driver.
+ * 1-enable, 0-disable
+ * Enable: Mandates the driver to do the further roams using the
+ * configuration parameters set through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET.
+ * Disable: Disables the driver/firmware roaming triggered through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET. Further roaming is
+ * expected to continue with the default configurations.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_STATUS: Unsigned 8-bit value.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET.
+ * Roam control status is obtained through this attribute.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CLEAR_ALL: Flag attribute to indicate the
+ * complete config set through QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET
+ * is to be cleared in the driver.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR
+ * and shall be ignored if used with other sub commands.
+ * If this attribute is specified along with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR, the driver shall ignore
+ * all other attributes, if there are any.
+ * If this attribute is not specified when the subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR is sent, the driver shall
+ * clear the data corresponding to the attributes specified.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME: Nested attribute to carry the
+ * list of frequencies and its type, represented by
+ * enum qca_vendor_attr_scan_freq_list_scheme.
+ * Frequency list and its type are mandatory for this attribute to set
+ * the frequencies.
+ * Frequency type is mandatory for this attribute to get the frequencies
+ * and the frequency list is obtained through
+ * QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST.
+ * Frequency list type is mandatory for this attribute to clear the
+ * frequencies.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of scan period in seconds to set.
+ * The value of scan period is obtained with the same attribute for get.
+ * Clears the scan period in the driver when specified with clear command.
+ * Scan period is the idle time in seconds between each subsequent
+ * channel scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of full scan period in seconds to set.
+ * The value of full scan period is obtained with the same attribute for
+ * get.
+ * Clears the full scan period in the driver when specified with clear
+ * command. Full scan period is the idle period in seconds between two
+ * successive full channel roam scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * The driver shall enable roaming by enabling corresponding roam triggers
+ * based on the trigger bits sent with this attribute.
+ * If this attribute is not configured, the driver shall proceed with
+ * default behavior.
+ * The bitmap configured is obtained with the same attribute for get.
+ * Clears the bitmap configured in driver when specified with clear
+ * command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA: Nested attribute signifying the
+ * weightage in percentage (%) to be given for each selection criteria.
+ * Different roam candidate selection criteria are represented by
+ * enum qca_vendor_attr_roam_candidate_selection_criteria.
+ * The driver shall select the roam candidate based on corresponding
+ * candidate selection scores sent.
+ *
+ * An empty nested attribute is used to indicate that no specific
+ * preference score/criteria is configured (i.e., to disable this mechanism
+ * in the set case and to show that the mechanism is disabled in the get
+ * case).
+ *
+ * Userspace can send multiple attributes out of this enum to the driver.
+ * Since this attribute represents the weight/percentage of preference for
+ * the respective selection criteria, it is preferred to configure 100%
+ * total weightage. The value in each attribute or cumulative weight of the
+ * values in all the nested attributes should not exceed 100%. The driver
+ * shall reject such configuration.
+ *
+ * If the weights configured through this attribute are less than 100%,
+ * the driver shall honor the weights (x%) passed for the corresponding
+ * selection criteria and choose/distribute rest of the weight (100-x)%
+ * for the other selection criteria, based on its internal logic.
+ *
+ * The selection criteria configured is obtained with the same
+ * attribute for get.
+ *
+ * Clears the selection criteria configured in the driver when specified
+ * with clear command.
+ */
+enum qca_vendor_attr_roam_control {
+ QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
+ QCA_ATTR_ROAM_CONTROL_STATUS = 2,
+ QCA_ATTR_ROAM_CONTROL_CLEAR_ALL = 3,
+ QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME= 4,
+ QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD = 5,
+ QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
+ QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
+ QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_MAX =
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roaming_config_params: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: Unsigned 32-bit value.
+ * Represents the different roam sub commands referred by
+ * enum qca_wlan_vendor_roaming_subcmd.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Unsigned 32-bit value.
+ * Represents the Request ID for the specific set of commands.
+ * This also helps to map specific set of commands to the respective
+ * ID / client. e.g., helps to identify the user entity configuring the
+ * Blacklist BSSID and accordingly clear the respective ones with the
+ * matching ID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
+ * 32-bit value.Represents the number of whitelist SSIDs configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: Nested attribute
+ * to carry the list of Whitelist SSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: SSID (binary attribute,
+ * 0..32 octets). Represents the white list SSID. Whitelist SSIDs
+ * represent the list of SSIDs to which the firmware/driver can consider
+ * to roam to.
+ *
+ * The following PARAM_A_BAND_XX attributes are applied to 5GHz BSSIDs when
+ * comparing with a 2.4GHz BSSID. They are not applied when comparing two
+ * 5GHz BSSIDs.The following attributes are set through the Roaming SUBCMD -
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold above which 5GHz RSSI is favored.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold below which 5GHz RSSI is penalized.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is boosted.
+ * boost=(RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is penalized.
+ * penalty=(5GHz_penalty_threshold-RSSI_measured)*5GHz_penalty_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: Unsigned 32-bit
+ * value, maximum boost that can be applied to a 5GHz RSSI.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: Unsigned 32-bit
+ * value, boost applied to current BSSID to ensure the currently
+ * associated BSSID is favored so as to prevent ping-pong situations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: Signed 32-bit
+ * value, RSSI below which "Alert" roam is enabled.
+ * "Alert" mode roaming - firmware is "urgently" hunting for another BSSID
+ * because the RSSI is low, or because many successive beacons have been
+ * lost or other bad link conditions.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: Unsigned 32-bit
+ * value. 1-Enable, 0-Disable. Represents "Lazy" mode, where
+ * firmware is hunting for a better BSSID or white listed SSID even though
+ * the RSSI of the link is good. The parameters enabling the roaming are
+ * configured through the PARAM_A_BAND_XX attrbutes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: Nested attribute,
+ * represents the BSSIDs preferred over others while evaluating them
+ * for the roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: Unsigned
+ * 32-bit value. Represents the number of preferred BSSIDs set.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: 6-byte MAC
+ * address representing the BSSID to be preferred.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: Signed
+ * 32-bit value, representing the modifier to be applied to the RSSI of
+ * the BSSID for the purpose of comparing it with other roam candidate.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
+ * represents the BSSIDs to get blacklisted for roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
+ * 32-bit value, represents the number of blacklisted BSSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
+ * address representing the Blacklisted BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
+ * indicates this BSSID blacklist as a hint to the driver. The driver can
+ * select this BSSID in the worst case (when no other BSSIDs are better).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
+ * set/get/clear the roam control config as
+ * defined @enum qca_vendor_attr_roam_control.
+ */
enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
@@ -3366,6 +3956,8 @@
/* Flag attribute indicates this BSSID blacklist as a hint */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
@@ -3373,22 +3965,63 @@
};
/*
- * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
- * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ * enum qca_wlan_vendor_roaming_subcmd: Referred by
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: Sub command to
+ * configure the white list SSIDs. These are configured through
+ * the following attributes.
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS: Sub command to
+ * configure the Roam params. These parameters are evaluated on the GScan
+ * results. Refers the attributes PARAM_A_BAND_XX above to configure the
+ * params.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM: Sets the Lazy roam. Uses
+ * the attribute QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE
+ * to enable/disable Lazy roam.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS: Sets the BSSID
+ * preference. Contains the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
+ * preference.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the Blacklist
+ * BSSIDs. Refers QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to
+ * set the same.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
+ * roam control config to the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET: Command to obtain the
+ * roam control config from driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable value to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR: Command to clear the
+ * roam control config in the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * The driver shall continue with its default roaming behavior when data
+ * corresponding to an attribute is cleared.
*/
-enum qca_wlan_vendor_attr_roam_subcmd {
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
-
- /* keep last */
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+enum qca_wlan_vendor_roaming_subcmd {
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_INVALID = 0,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST = 1,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM = 3,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS = 4,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PARAMS = 5,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID = 6,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET = 7,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET = 8,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR = 9,
};
enum qca_wlan_vendor_attr_gscan_config_params {
@@ -3756,8 +4389,8 @@
/* Unsigned 32-bit value; a GSCAN Capabilities attribute.
* This is used to limit the maximum number of BSSIDs while sending
- * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
- * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+ * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID and attribute
* QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
*/
QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
@@ -3859,6 +4492,44 @@
QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
/* Represents the reason that LTE co-exist in the current band. */
QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+ /* Represents the reason that generic, uncategorized interference has
+ * been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_GENERIC_INTERFERENCE,
+ /* Represents the reason that excessive 802.11 interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_80211_INTERFERENCE,
+ /* Represents the reason that generic Continuous Wave (CW) interference
+ * has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_CW_INTERFERENCE,
+ /* Represents the reason that Microwave Oven (MWO) interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_MWO_INTERFERENCE,
+ /* Represents the reason that generic Frequency-Hopping Spread Spectrum
+ * (FHSS) interference has been found in the current channel. This may
+ * include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_FHSS_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Frequency-Hopping
+ * Spread Spectrum (FHSS) interference has been found in the current
+ * channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_FHSS_INTERFERENCE,
+ /* Represents the reason that generic Wideband (WB) interference has
+ * been found in the current channel. This may include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_WB_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Wideband (WB)
+ * interference has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_WB_INTERFERENCE,
+ /* Represents the reason that Jammer interference has been found in the
+ * current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
};
/**
@@ -4026,6 +4697,46 @@
*/
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11,
+ /*
+ * VHT segment 0 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * should be used.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = 12,
+
+ /*
+ * VHT segment 1 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * should be considered.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -4126,9 +4837,100 @@
};
/**
- * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * enum qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
* in priority order as decided after ACS operation in userspace.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON: Required (u8).
+ * One of reason code from enum qca_wlan_vendor_acs_select_reason.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY: Required (u8).
+ * Primary channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY: Required (u8).
+ * Secondary channel number, required only for 160 and 80+80 MHz bandwidths.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0: Required (u8).
+ * VHT seg0 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1: Required (u8).
+ * VHT seg1 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH: Required (u8).
+ * Takes one of enum nl80211_chan_width values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY: Required (u32)
+ * Primary channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY: Required (u32)
+ * Secondary channel frequency in MHz used for HT 40 MHz channels.
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0: Required (u32)
+ * VHT seg0 channel frequency in MHz
+ * Note: If user-space application has no support of the 6GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1: Required (u32)
+ * VHT seg1 channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
*/
enum qca_wlan_vendor_attr_external_acs_channels {
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
@@ -4159,6 +4961,12 @@
/* Channel width (u8). Takes one of enum nl80211_chan_width values. */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST = 9,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY = 10,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY = 11,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 = 12,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
@@ -4676,8 +5484,18 @@
* 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 =
@@ -7102,4 +7920,130 @@
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
};
+/**
+ * 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/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,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext - Defines attributes to be
+ * used with vendor command/event QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE: Required
+ * Nested attribute containing multiple ranges with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START: Required (u32)
+ * Starting center frequency in MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END: Required (u32)
+ * Ending center frequency in MHz.
+ */
+enum qca_wlan_vendor_attr_avoid_frequency_ext {
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE = 1,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START = 2,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3,
+
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX =
+ 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 0da7145..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"
@@ -45,6 +47,7 @@
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
+ tmp->order_len = crypto_ec_order_len(tmp->ec);
tmp->order = crypto_ec_get_order(tmp->ec);
return 0;
}
@@ -69,6 +72,7 @@
}
tmp->prime = tmp->prime_buf;
+ tmp->order_len = tmp->dh->order_len;
tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
tmp->dh->order_len);
if (tmp->order_buf == NULL) {
@@ -105,6 +109,8 @@
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;
@@ -275,7 +281,7 @@
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
{
- u8 counter, k = 40;
+ u8 counter, k;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[3];
size_t len[3];
@@ -346,6 +352,8 @@
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
+ k = dragonfly_min_pwe_loop_iter(sae->group);
+
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@@ -427,13 +435,6 @@
}
-static int sae_modp_group_require_masking(int group)
-{
- /* Groups for which pwd-value is likely to be >= p frequently */
- return group == 22 || group == 23 || group == 24;
-}
-
-
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
@@ -482,7 +483,7 @@
len[num_elem] = sizeof(counter);
num_elem++;
- k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
+ k = dragonfly_min_pwe_loop_iter(sae->group);
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@@ -528,6 +529,742 @@
}
+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)
{
@@ -607,10 +1344,66 @@
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);
}
@@ -688,47 +1481,124 @@
}
+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;
- 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);
- crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
- wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
+ 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;
- 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);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
+
+ 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
+ * (commit-scalar + peer-commit-scalar) mod r part as a bit string by
+ * zero padding it from left to the length of the order (in full
+ * octets). */
+ crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+ 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;
+ 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;
}
@@ -791,6 +1661,16 @@
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);
+ }
}
@@ -846,9 +1726,19 @@
}
+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;
@@ -869,6 +1759,8 @@
* 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);
@@ -886,12 +1778,27 @@
* 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);
@@ -1058,11 +1965,11 @@
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)",
@@ -1075,8 +1982,8 @@
}
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);
@@ -1084,19 +1991,39 @@
}
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;
@@ -1110,7 +2037,7 @@
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);
@@ -1123,10 +2050,17 @@
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.
@@ -1154,12 +2088,12 @@
}
-static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const u8 *element1, size_t element1_len,
- const struct crypto_bignum *scalar2,
- const u8 *element2, size_t element2_len,
- u8 *confirm)
+static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const u8 *element1, size_t element1_len,
+ const struct crypto_bignum *scalar2,
+ const u8 *element2, size_t element2_len,
+ u8 *confirm)
{
const u8 *addr[5];
size_t len[5];
@@ -1173,72 +2107,81 @@
* verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
* PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
*/
+ if (crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+ sae->tmp->prime_len) < 0)
+ return -1;
addr[0] = sc;
len[0] = 2;
- crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
- sae->tmp->prime_len);
addr[1] = scalar_b1;
len[1] = sae->tmp->prime_len;
addr[2] = element1;
len[2] = element1_len;
- crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
- sae->tmp->prime_len);
addr[3] = scalar_b2;
len[3] = sae->tmp->prime_len;
addr[4] = element2;
len[4] = element2_len;
- 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);
}
-static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_ec_point *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_ec_point *element2,
- u8 *confirm)
+static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_ec_point *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_ec_point *element2,
+ u8 *confirm)
{
u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
- crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
- element_b1 + sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
- element_b2 + sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
- scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+ if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+ element_b1 + sae->tmp->prime_len) < 0 ||
+ crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+ element_b2 + sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1,
+ 2 * sae->tmp->prime_len,
+ scalar2, element_b2, 2 * sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
-static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_bignum *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_bignum *element2,
- u8 *confirm)
+static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_bignum *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_bignum *element2,
+ u8 *confirm)
{
u8 element_b1[SAE_MAX_PRIME_LEN];
u8 element_b2[SAE_MAX_PRIME_LEN];
- crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
- sae->tmp->prime_len);
- crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
- sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
- scalar2, element_b2, sae->tmp->prime_len, confirm);
+ if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+ sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+ scalar2, element_b2, sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
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);
@@ -1250,59 +2193,63 @@
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 (len < 2 + SHA256_MAC_LEN) {
+ if (!sae->tmp)
+ return -1;
+
+ 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;
}
if (sae->tmp->ec) {
if (!sae->tmp->peer_commit_element_ecc ||
- !sae->tmp->own_commit_element_ecc)
+ !sae->tmp->own_commit_element_ecc ||
+ sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ verifier) < 0)
return -1;
- sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ecc,
- sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ecc,
- verifier);
} else {
if (!sae->tmp->peer_commit_element_ffc ||
- !sae->tmp->own_commit_element_ffc)
+ !sae->tmp->own_commit_element_ffc ||
+ sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ verifier) < 0)
return -1;
- sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ffc,
- sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ffc,
- verifier);
}
- 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 3eb6e32..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;
@@ -33,6 +34,7 @@
struct crypto_bignum *sae_rand;
struct crypto_ec *ec;
int prime_len;
+ int order_len;
const struct dh_group *dh;
const struct crypto_bignum *prime;
const struct crypto_bignum *order;
@@ -42,6 +44,20 @@
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 {
@@ -67,14 +83,28 @@
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/version.h b/src/common/version.h
index 031d1be..0235c9b 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
-#define VERSION_STR "2.9-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.10-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index ed2d1c2..ea9f7a2 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -212,11 +212,9 @@
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
#ifdef CONFIG_SAE
@@ -410,14 +408,10 @@
return -1;
#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
if (sha256_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
-#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
- return -1;
-#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
#ifdef CONFIG_DPP
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -692,7 +686,7 @@
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;
@@ -723,7 +717,7 @@
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;
@@ -756,10 +750,12 @@
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;
@@ -826,6 +822,12 @@
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
@@ -892,12 +894,10 @@
parse->r0kh_id = pos;
parse->r0kh_id_len = len;
break;
-#ifdef CONFIG_IEEE80211W
case FTIE_SUBELEM_IGTK:
parse->igtk = pos;
parse->igtk_len = len;
break;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
case FTIE_SUBELEM_OCI:
parse->oci = pos;
@@ -958,6 +958,7 @@
"RSN IE: %d", ret);
return -1;
}
+ parse->rsn_capab = data.capabilities;
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt;
@@ -968,6 +969,13 @@
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))
@@ -989,9 +997,11 @@
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie_sha384->mic,
sizeof(ftie_sha384->mic));
+ parse->fte_anonce = ftie_sha384->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie_sha384->anonce,
WPA_NONCE_LEN);
+ parse->fte_snonce = ftie_sha384->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie_sha384->snonce,
WPA_NONCE_LEN);
@@ -1008,8 +1018,10 @@
ftie->mic_control, 2);
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie->mic, sizeof(ftie->mic));
+ parse->fte_anonce = ftie->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie->anonce, WPA_NONCE_LEN);
+ parse->fte_snonce = ftie->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
@@ -1046,6 +1058,8 @@
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");
@@ -1087,10 +1101,8 @@
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
return WPA_CIPHER_GCMP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
@@ -1125,12 +1137,10 @@
return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
return WPA_KEY_MGMT_IEEE8021X_SHA256;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
@@ -1170,7 +1180,6 @@
}
-#ifdef CONFIG_IEEE80211W
int wpa_cipher_valid_mgmt_group(int cipher)
{
return cipher == WPA_CIPHER_AES_128_CMAC ||
@@ -1178,7 +1187,6 @@
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
}
-#endif /* CONFIG_IEEE80211W */
/**
@@ -1203,11 +1211,7 @@
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
-#ifdef CONFIG_IEEE80211W
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-#else /* CONFIG_IEEE80211W */
- data->mgmt_group_cipher = 0;
-#endif /* CONFIG_IEEE80211W */
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
@@ -1282,13 +1286,11 @@
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
"pairwise cipher", __func__);
return -1;
}
-#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
@@ -1340,7 +1342,6 @@
}
}
-#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
@@ -1353,7 +1354,6 @@
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
if (left > 0) {
wpa_hexdump(MSG_DEBUG,
@@ -1852,11 +1852,9 @@
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
#endif /* CONFIG_FILS || CONFIG_SHA384 */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (wpa_key_mgmt_sha256(akmp)) {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
} else {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
@@ -2007,12 +2005,10 @@
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return "WPA2-EAP-SHA256";
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_WPS:
return "WPS";
case WPA_KEY_MGMT_SAE:
@@ -2075,6 +2071,16 @@
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ if (akm & WPA_KEY_MGMT_SAE)
+ return RSN_AUTH_KEY_MGMT_SAE;
+ if (akm & WPA_KEY_MGMT_FT_SAE)
+ return RSN_AUTH_KEY_MGMT_FT_SAE;
+ if (akm & WPA_KEY_MGMT_OWE)
+ return RSN_AUTH_KEY_MGMT_OWE;
+ if (akm & WPA_KEY_MGMT_DPP)
+ return RSN_AUTH_KEY_MGMT_DPP;
+ if (akm & WPA_KEY_MGMT_OSEN)
+ return RSN_AUTH_KEY_MGMT_OSEN;
return 0;
}
@@ -2116,7 +2122,6 @@
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
@@ -2131,11 +2136,10 @@
start += 2 + start[1];
}
if (start >= end) {
- wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
start, 2 + start[1]);
/* Find start of PMKID-Count */
@@ -2161,8 +2165,8 @@
/* Skip RSN Capabilities */
rpos += 2;
if (rpos > rend) {
- wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR,
+ "RSN: Could not parse RSNE in IEs data");
return -1;
}
}
@@ -2193,7 +2197,7 @@
* PMKID(s) first before adding the new one.
*/
wpa_printf(MSG_DEBUG,
- "FT: Remove %u old PMKID(s) from RSN IE",
+ "RSN: Remove %u old PMKID(s) from RSNE",
num_pmkid);
after = rpos + 2 + num_pmkid * PMKID_LEN;
os_memmove(rpos + 2, after, rend - after);
@@ -2208,14 +2212,13 @@
start[1] += PMKID_LEN;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
- "(PMKID inserted)", start, 2 + start[1]);
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
+ start, 2 + start[1]);
*ies_len += added;
return 0;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int wpa_cipher_key_len(int cipher)
@@ -2600,3 +2603,266 @@
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 e83d688..beb1ecd 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -104,9 +104,7 @@
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
-#endif /* CONFIG_IEEE80211W */
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
@@ -130,10 +128,8 @@
#pragma pack(push, 1)
#endif /* _MSC_VER */
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
-#endif /* CONFIG_IEEE80211W */
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -226,12 +222,10 @@
size_t gtk_len;
};
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk {
u8 igtk[WPA_IGTK_MAX_LEN];
size_t igtk_len;
};
-#endif /* CONFIG_IEEE80211W */
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
@@ -291,14 +285,12 @@
be16 error_type;
} STRUCT_PACKED;
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211W */
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -372,7 +364,9 @@
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,
@@ -451,8 +445,11 @@
size_t gtk_len;
const u8 *r0kh_id;
size_t r0kh_id_len;
+ const u8 *fte_anonce;
+ const u8 *fte_snonce;
const u8 *rsn;
size_t rsn_len;
+ u16 rsn_capab;
const u8 *rsn_pmkid;
const u8 *tie;
size_t tie_len;
@@ -466,11 +463,67 @@
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/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index b24ae63..70ecf5d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -168,6 +168,7 @@
#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
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_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 @@
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 @@
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_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 fb278c2..783b293 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1283,6 +1283,24 @@
}
+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)
@@ -1295,13 +1313,7 @@
int crypto_bignum_to_bin(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen)
{
-#ifdef OPENSSL_IS_BORINGSSL
-#else /* OPENSSL_IS_BORINGSSL */
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-#else
int num_bytes, offset;
-#endif
-#endif /* OPENSSL_IS_BORINGSSL */
if (TEST_FAIL())
return -1;
@@ -1309,14 +1321,18 @@
if (padlen > buflen)
return -1;
+ if (padlen) {
#ifdef OPENSSL_IS_BORINGSSL
- if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
- return -1;
- return padlen;
+ if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
+ return -1;
+ return padlen;
#else /* OPENSSL_IS_BORINGSSL */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
- return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
-#else
+ return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
+#endif
+#endif
+ }
+
num_bytes = BN_num_bytes((const BIGNUM *) a);
if ((size_t) num_bytes > buflen)
return -1;
@@ -1329,8 +1345,6 @@
BN_bn2bin((const BIGNUM *) a, buf + offset);
return num_bytes + offset;
-#endif
-#endif /* OPENSSL_IS_BORINGSSL */
}
@@ -1453,6 +1467,28 @@
}
+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,
@@ -1476,6 +1512,27 @@
}
+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)
{
@@ -1686,6 +1743,18 @@
}
+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)
@@ -2063,13 +2132,17 @@
secret = wpabuf_alloc(secret_len);
if (!secret)
goto fail;
- if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
- &secret_len) != 1) {
+ if (EVP_PKEY_derive(ctx, wpabuf_put(secret, 0), &secret_len) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: EVP_PKEY_derive(2) failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
+ if (secret->size != secret_len)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: EVP_PKEY_derive(2) changed secret_len %d -> %d",
+ (int) secret->size, (int) secret_len);
+ wpabuf_put(secret, secret_len);
done:
BN_free(x);
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_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 @@
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_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_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_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/crypto/sha384-tlsprf.c b/src/crypto/sha384-tlsprf.c
new file mode 100644
index 0000000..9ff96ac
--- /dev/null
+++ b/src/crypto/sha384-tlsprf.c
@@ -0,0 +1,71 @@
+/*
+ * TLS PRF P_SHA384
+ * Copyright (c) 2011-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+
+
+/**
+ * tls_prf_sha384 - Pseudo-Random Function for TLS v1.2 (P_SHA384, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 5246, Chapter 5.
+ */
+int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+ size_t clen;
+ u8 A[SHA384_MAC_LEN];
+ u8 P[SHA384_MAC_LEN];
+ size_t pos;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = A;
+ len[0] = SHA384_MAC_LEN;
+ addr[1] = (unsigned char *) label;
+ len[1] = os_strlen(label);
+ addr[2] = seed;
+ len[2] = seed_len;
+
+ /*
+ * RFC 5246, Chapter 5
+ * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+ * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+ * PRF(secret, label, seed) = P_SHA384(secret, label + seed)
+ */
+
+ if (hmac_sha384_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+ return -1;
+
+ pos = 0;
+ while (pos < outlen) {
+ if (hmac_sha384_vector(secret, secret_len, 3, addr, len, P) <
+ 0 ||
+ hmac_sha384(secret, secret_len, A, SHA384_MAC_LEN, A) < 0)
+ return -1;
+
+ clen = outlen - pos;
+ if (clen > SHA384_MAC_LEN)
+ clen = SHA384_MAC_LEN;
+ os_memcpy(out + pos, P, clen);
+ pos += clen;
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
index 2241425..d946907 100644
--- a/src/crypto/sha384.h
+++ b/src/crypto/sha384.h
@@ -20,6 +20,9 @@
int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
+int tls_prf_sha384(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 9718ceb..f3803bd 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2204,7 +2204,9 @@
continue;
wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
- tod = 1;
+ tod = 1; /* TOD-STRICT */
+ else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
+ tod = 2; /* TOD-TOFU */
}
return tod;
@@ -2312,6 +2314,38 @@
}
+static void debug_print_cert(X509 *cert, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ X509_print(out, cert);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
+ }
+ os_free(txt);
+ }
+
+ BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -2332,6 +2366,8 @@
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
+ os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
+ debug_print_cert(err_cert, buf);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
@@ -4674,41 +4710,6 @@
}
-static void debug_print_cert(X509 *cert, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
-
- if (wpa_debug_level > MSG_DEBUG)
- return;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- X509_print(out, cert);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (!txt) {
- BIO_free(out);
- return;
- }
-
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
- }
- os_free(txt);
-
- BIO_free(out);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
static int ocsp_resp_cb(SSL *s, void *arg)
{
struct tls_connection *conn = arg;
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index 83704ff..d222d14 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -141,7 +141,7 @@
if (get > (wpabuf_len(data->in_data) - data->consumed))
get = wpabuf_len(data->in_data) - data->consumed;
- os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+ os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->consumed, get);
data->consumed += get;
if (get == 0)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8a5cdb8..ad68a07 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -213,6 +213,24 @@
};
/**
+ * 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 @@
* 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 @@
* 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 @@
* 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;
};
/**
@@ -1074,6 +1104,14 @@
int req_key_mgmt_offload;
/**
+ * req_handshake_offload - Request EAPOL handshake offload
+ *
+ * Request EAPOL handshake offload for this connection if the device
+ * supports it.
+ */
+ int req_handshake_offload;
+
+ /**
* Flag for indicating whether this association includes support for
* RRM (Radio Resource Measurements)
*/
@@ -1434,6 +1472,21 @@
* type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
*/
const struct wpabuf *civic;
+
+ /**
+ * he_spr - Whether Spatial Reuse is enabled
+ */
+ int he_spr;
+
+ /**
+ * he_spr_srg_obss_pd_min_offset - Minimum TX power offset
+ */
+ int he_spr_srg_obss_pd_min_offset;
+
+ /**
+ * he_spr_srg_obss_pd_max_offset - Maximum TX power offset
+ */
+ int he_spr_srg_obss_pd_max_offset;
};
struct wpa_driver_mesh_bss_params {
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 840d4ff..eac3ae8 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -59,10 +59,6 @@
#include "netlink.h"
#include "linux_ioctl.h"
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS)
-#define ATHEROS_USE_RAW_RECEIVE
-#endif
-
struct atheros_driver_data {
struct hostapd_data *hapd; /* back pointer */
@@ -366,13 +362,11 @@
v = 0;
if (params->rsn_preauth)
v |= BIT(0);
-#ifdef CONFIG_IEEE80211W
if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
v |= BIT(7);
if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
v |= BIT(6);
}
-#endif /* CONFIG_IEEE80211W */
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
@@ -534,7 +528,6 @@
cipher = IEEE80211_CIPHER_AES_GCM_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
cipher = IEEE80211_CIPHER_AES_CMAC;
break;
@@ -549,7 +542,6 @@
cipher = IEEE80211_CIPHER_AES_GMAC_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
__func__, alg);
@@ -856,7 +848,7 @@
return 0;
}
-#ifdef ATHEROS_USE_RAW_RECEIVE
+
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -953,7 +945,7 @@
break;
}
}
-#endif /* ATHEROS_USE_RAW_RECEIVE */
+
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -965,11 +957,9 @@
#ifdef CONFIG_WPS
filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_WNM */
@@ -1069,7 +1059,6 @@
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
static int
atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
{
@@ -1169,7 +1158,7 @@
}
return ret;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
+
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1315,7 +1304,6 @@
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
@@ -1339,8 +1327,6 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */
-#ifdef ATHEROS_USE_RAW_RECEIVE
} else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
@@ -1353,7 +1339,6 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* ATHEROS_USE_RAW_RECEIVE */
}
}
@@ -1973,8 +1958,6 @@
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
-
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
int noack, unsigned int freq,
const u16 *csa_offs, size_t csa_offs_len)
@@ -1999,7 +1982,6 @@
return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
sizeof(struct ieee80211req_mgmtbuf) + data_len);
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
@@ -2283,11 +2265,9 @@
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 82ca061..8667ee5 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1661,6 +1661,17 @@
bsd_global_init(void *ctx)
{
struct bsd_driver_global *global;
+#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
+ unsigned char msgfilter[] = {
+ RTM_IEEE80211,
+#ifndef HOSTAPD
+ RTM_IFINFO, RTM_IFANNOUNCE,
+#endif
+ };
+#endif
+#ifdef ROUTE_MSGFILTER
+ unsigned int i, msgfilter_mask;
+#endif
global = os_zalloc(sizeof(*global));
if (global == NULL)
@@ -1683,6 +1694,21 @@
goto fail;
}
+#if defined(RO_MSGFILTER)
+ if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER,
+ &msgfilter, sizeof(msgfilter)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s",
+ strerror(errno));
+#elif defined(ROUTE_MSGFILTER)
+ msgfilter_mask = 0;
+ for (i = 0; i < (sizeof(msgfilter) / sizeof(msgfilter[0])); i++)
+ msgfilter_mask |= ROUTE_FILTER(msgfilter[i]);
+ if (setsockopt(global->route, PF_ROUTE, ROUTE_MSGFILTER,
+ &msgfilter_mask, sizeof(msgfilter_mask)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,ROUTE_MSGFILTER]: %s",
+ strerror(errno));
+#endif
+
global->event_buf_len = rtbuf_len();
global->event_buf = os_malloc(global->event_buf_len);
if (global->event_buf == NULL) {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 45835a2..4c8dcad 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2240,7 +2240,6 @@
6) < 0)
ret = -1;
#endif /* CONFIG_DPP */
-#ifdef CONFIG_IEEE80211W
#ifdef CONFIG_OCV
/* SA Query Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
@@ -2249,7 +2248,6 @@
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_TDLS
if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
/* TDLS Discovery Response */
@@ -2385,11 +2383,9 @@
/* FT Action frames */
if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
/* SA Query */
if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
/* Protected Dual of Public Action */
if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
ret = -1;
@@ -3015,7 +3011,8 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex;
- struct nl_msg *msg = NULL;
+ struct nl_msg *msg;
+ struct nl_msg *key_msg;
int ret;
int tdls = 0;
@@ -3049,26 +3046,31 @@
(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return nl80211_set_pmk(drv, key, key_len, addr);
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return -ENOBUFS;
+
if (alg == WPA_ALG_NONE) {
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
if (!msg)
- return -ENOBUFS;
+ goto fail2;
} else {
u32 suite;
suite = wpa_alg_to_cipher_suite(alg, key_len);
if (!suite)
- goto fail;
+ goto fail2;
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
- if (!msg ||
- nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
- nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
+ if (!msg)
+ goto fail2;
+ if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
+ nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
}
if (seq && seq_len) {
- if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
+ if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
goto fail;
wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
}
@@ -3080,7 +3082,7 @@
if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
- if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
+ if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
NL80211_KEYTYPE_GROUP))
goto fail;
}
@@ -3089,14 +3091,18 @@
wpa_printf(MSG_DEBUG, " broadcast key");
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
}
- if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+ if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
@@ -3115,34 +3121,46 @@
!is_broadcast_ether_addr(addr))
return ret;
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return -ENOBUFS;
+
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
- if (!msg ||
- nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
- nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
- alg == WPA_ALG_BIP_GMAC_128 ||
- alg == WPA_ALG_BIP_GMAC_256 ||
- alg == WPA_ALG_BIP_CMAC_256) ?
- NL80211_ATTR_KEY_DEFAULT_MGMT :
- NL80211_ATTR_KEY_DEFAULT))
+ if (!msg)
+ goto fail2;
+ if (!key_msg ||
+ nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_flag(key_msg, (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) ?
+ NL80211_KEY_DEFAULT_MGMT :
+ NL80211_KEY_DEFAULT))
goto fail;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
} else if (addr) {
struct nlattr *types;
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
}
+ if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
+ goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret == -ENOENT)
ret = 0;
@@ -3154,6 +3172,9 @@
fail:
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
+fail2:
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
return -ENOBUFS;
}
@@ -4286,6 +4307,23 @@
nla_nest_end(msg, ftm);
}
+#ifdef CONFIG_IEEE80211AX
+ if (params->he_spr) {
+ struct nlattr *spr;
+
+ spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
+ wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
+
+ if (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ params->he_spr_srg_obss_pd_min_offset) ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ params->he_spr_srg_obss_pd_max_offset))
+ goto fail;
+
+ nla_nest_end(msg, spr);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -4344,6 +4382,10 @@
static int nl80211_put_freq_params(struct nl_msg *msg,
const struct hostapd_freq_params *freq)
{
+ enum hostapd_hw_mode hw_mode;
+ int is_24ghz;
+ u8 channel;
+
wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
return -ENOBUFS;
@@ -4352,7 +4394,11 @@
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
- if (freq->vht_enabled || freq->he_enabled) {
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
+
+ if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
enum nl80211_chan_width cw;
wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
@@ -4408,6 +4454,15 @@
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);
@@ -4700,8 +4755,9 @@
goto fail;
#endif /* CONFIG_MESH */
- if ((!params->set || FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
- (params->flags & WPA_STA_WMM)) {
+ if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+ FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
+ (params->flags & WPA_STA_WMM)) {
struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
@@ -5486,6 +5542,18 @@
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);
@@ -5632,7 +5700,7 @@
return -1;
}
- if (params->req_key_mgmt_offload &&
+ if (params->req_handshake_offload &&
(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
@@ -5694,7 +5762,8 @@
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;
@@ -5849,7 +5918,8 @@
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 {
@@ -9453,7 +9523,7 @@
QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
!(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
WPA_SUPPLICANT_CLIENT_ID) ||
nla_put_u32(msg,
@@ -9488,6 +9558,40 @@
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 */
@@ -10745,22 +10849,37 @@
{
int fd, len;
char tmp[128];
+ int ret = 0;
fd = open(name, O_RDWR);
if (fd < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+ int level;
+ /*
+ * Flags may not exist on older kernels, or while we're tearing
+ * down a disappearing device.
+ */
+ if (errno == ENOENT) {
+ ret = 0;
+ level = MSG_DEBUG;
+ } else {
+ ret = -1;
+ level = MSG_ERROR;
+ }
+ wpa_printf(level, "nl80211: Failed to open %s: %s",
name, strerror(errno));
- return fd;
+ return ret;
}
len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
len = write(fd, tmp, len);
- if (len < 0)
+ if (len < 0) {
+ ret = -1;
wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
name, strerror(errno));
+ }
close(fd);
- return 0;
+ return ret;
}
@@ -10875,6 +10994,14 @@
int ret = -1;
enum nl80211_auth_type type;
+ /* Update Connection Params is intended for drivers that implement
+ * internal SME and expect these updated connection params from
+ * wpa_supplicant. Do not send this request for the drivers using
+ * SME from wpa_supplicant.
+ */
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
+ return 0;
+
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
if (!msg)
goto fail;
@@ -11129,6 +11256,7 @@
.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 @@
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 @@
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 @@
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 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 @@
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/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 4d4a05d..32c2971 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1767,11 +1767,9 @@
case WPA_ALG_PMK:
ext->alg = IW_ENCODE_ALG_PMK;
break;
-#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
ext->alg = IW_ENCODE_ALG_AES_CMAC;
break;
-#endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
__FUNCTION__, alg);
@@ -2201,7 +2199,6 @@
IW_AUTH_RX_UNENCRYPTED_EAPOL,
allow_unencrypted_eapol) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
switch (params->mgmt_frame_protection) {
case NO_MGMT_FRAME_PROTECTION:
value = IW_AUTH_MFP_DISABLED;
@@ -2215,7 +2212,6 @@
};
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
if (params->freq.freq &&
wpa_driver_wext_set_freq(drv, params->freq.freq) < 0)
ret = -1;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 6f09d15..beee59c 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -52,6 +52,11 @@
#define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
+#define NL80211_EDMG_BW_CONFIG_MIN 4
+#define NL80211_EDMG_BW_CONFIG_MAX 15
+#define NL80211_EDMG_CHANNELS_MIN 1
+#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */
+
/**
* DOC: Station handling
*
@@ -235,6 +240,15 @@
*/
/**
+ * DOC: SAE authentication offload
+ *
+ * By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they
+ * support offloading SAE authentication for WPA3-Personal networks. In
+ * %NL80211_CMD_CONNECT the password for SAE should be specified using
+ * %NL80211_ATTR_SAE_PASSWORD.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -648,7 +662,9 @@
* is used during CSA period.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
- * time if it is known that it is no longer necessary.
+ * time if it is known that it is no longer necessary. This command is
+ * also sent as an event whenever the driver has completed the off-channel
+ * wait time.
* @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
* @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
@@ -2341,6 +2357,22 @@
* should be picking up the lowest tx power, either tx power per-interface
* or per-station.
*
+ * @NL80211_ATTR_SAE_PASSWORD: attribute for passing SAE password material. It
+ * is used with %NL80211_CMD_CONNECT to provide password for offloading
+ * SAE authentication for WPA3-Personal networks.
+ *
+ * @NL80211_ATTR_TWT_RESPONDER: Enable target wait time responder support.
+ *
+ * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
+ * functionality.
+ *
+ * @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute)
+ * @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations. (u8 attribute)
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2794,6 +2826,15 @@
NL80211_ATTR_STA_TX_POWER_SETTING,
NL80211_ATTR_STA_TX_POWER,
+ NL80211_ATTR_SAE_PASSWORD,
+
+ NL80211_ATTR_TWT_RESPONDER,
+
+ NL80211_ATTR_HE_OBSS_PD,
+
+ NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2844,7 +2885,7 @@
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
#define NL80211_HE_MIN_CAPABILITY_LEN 16
-#define NL80211_HE_MAX_CAPABILITY_LEN 51
+#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -3175,6 +3216,8 @@
* sent to the station (u64, usec)
* @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station
+ * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds)
+ * of STA's association
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3221,6 +3264,7 @@
NL80211_STA_INFO_TX_DURATION,
NL80211_STA_INFO_AIRTIME_WEIGHT,
NL80211_STA_INFO_AIRTIME_LINK_METRIC,
+ NL80211_STA_INFO_ASSOC_AT_BOOTTIME,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3402,6 +3446,12 @@
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
* attributes from &enum nl80211_band_iftype_attr
+ * @NL80211_BAND_ATTR_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251.
+ * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -3419,6 +3469,9 @@
NL80211_BAND_ATTR_VHT_CAPA,
NL80211_BAND_ATTR_IFTYPE_DATA,
+ NL80211_BAND_ATTR_EDMG_CHANNELS,
+ NL80211_BAND_ATTR_EDMG_BW_CONFIG,
+
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -3817,6 +3870,8 @@
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
* (on this channel or globally)
* @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_SURVEY_INFO_TIME_BSS_RX: amount of time the radio spent
+ * receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -3833,6 +3888,7 @@
NL80211_SURVEY_INFO_TIME_TX,
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
+ NL80211_SURVEY_INFO_TIME_BSS_RX,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -4406,6 +4462,7 @@
enum nl80211_wpa_versions {
NL80211_WPA_VERSION_1 = 1 << 0,
NL80211_WPA_VERSION_2 = 1 << 1,
+ NL80211_WPA_VERSION_3 = 1 << 2,
};
/**
@@ -4516,6 +4573,7 @@
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
+ * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4523,6 +4581,7 @@
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
+ NL80211_BAND_6GHZ,
NUM_NL80211_BANDS,
};
@@ -5314,7 +5373,7 @@
NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
- NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31,
};
/**
@@ -5422,6 +5481,9 @@
* @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
* to a station.
*
+ * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
+ * station mode (SAE password is passed as part of the connect command).
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5466,6 +5528,7 @@
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6464,4 +6527,26 @@
NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
};
+/**
+ * enum nl80211_obss_pd_attributes - OBSS packet detection attributes
+ * @__NL80211_HE_OBSS_PD_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset.
+ *
+ * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal
+ * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute.
+ */
+enum nl80211_obss_pd_attributes {
+ __NL80211_HE_OBSS_PD_ATTR_INVALID,
+
+ NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+
+ /* keep last */
+ __NL80211_HE_OBSS_PD_ATTR_LAST,
+ NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
+};
+
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 51a15d7..e27b965 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -63,7 +63,7 @@
* the payload regardless of whether the packet used the expanded EAP header or
* not.
*/
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen)
{
const struct eap_hdr *hdr;
@@ -125,8 +125,8 @@
* function to allocate the message buffers. The returned buffer has room for
* payload_len bytes and has the EAP header and Type field already filled in.
*/
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier)
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier)
{
struct wpabuf *buf;
struct eap_hdr *hdr;
@@ -196,7 +196,7 @@
* @msg: Buffer starting with an EAP header
* Returns: The EAP Type after the EAP header
*/
-EapType eap_get_type(const struct wpabuf *msg)
+enum eap_type eap_get_type(const struct wpabuf *msg)
{
if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
return EAP_TYPE_NONE;
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index e62f167..e40cabe 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -20,13 +20,13 @@
};
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen);
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier);
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier);
void eap_update_len(struct wpabuf *msg);
u8 eap_get_id(const struct wpabuf *msg);
-EapType eap_get_type(const struct wpabuf *msg);
+enum eap_type eap_get_type(const struct wpabuf *msg);
int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
int stop_at_keyname);
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index bc3047c..70999c4 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -64,7 +64,7 @@
* EAP Method Types as allocated by IANA:
* http://www.iana.org/assignments/eap-numbers
*/
-typedef enum {
+enum eap_type {
EAP_TYPE_NONE = 0,
EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
@@ -94,7 +94,7 @@
EAP_TYPE_EKE = 53 /* RFC 6124 */,
EAP_TYPE_TEAP = 55 /* RFC 7170 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
-} EapType;
+};
/* SMI Network Management Private Enterprise Code for vendor specific types */
diff --git a/src/eap_common/eap_teap_common.c b/src/eap_common/eap_teap_common.c
index fbca1b5..ffb9a62 100644
--- a/src/eap_common/eap_teap_common.c
+++ b/src/eap_common/eap_teap_common.c
@@ -17,6 +17,9 @@
#include "eap_teap_common.h"
+static int tls_cipher_suite_mac_sha384(u16 cs);
+
+
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
{
struct teap_tlv_hdr hdr;
@@ -67,24 +70,27 @@
}
-static int eap_teap_tls_prf(const u8 *secret, size_t secret_len,
+static int eap_teap_tls_prf(u16 tls_cs, const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen)
{
/* TODO: TLS-PRF for TLSv1.3 */
+ if (tls_cipher_suite_mac_sha384(tls_cs))
+ return tls_prf_sha384(secret, secret_len, label, seed, seed_len,
+ out, outlen);
return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
out, outlen);
}
-int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk)
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk)
{
/*
* RFC 7170, Section 5.4: EAP Master Session Key Generation
* MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
*/
- if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
"Session Key Generating Function", (u8 *) "", 0,
msk, EAP_TEAP_KEY_LEN) < 0)
return -1;
@@ -94,7 +100,7 @@
}
-int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk)
{
/*
* RFC 7170, Section 5.4: EAP Master Session Key Generation
@@ -102,7 +108,7 @@
* "Extended Session Key Generating Function", 64)
*/
- if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
"Extended Session Key Generating Function",
(u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
return -1;
@@ -112,7 +118,7 @@
}
-int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk, u8 *cmk)
{
u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
int res;
@@ -123,7 +129,7 @@
* published. For now, derive CMK[0] based on S-IMCK[0] and
* IMSK of 32 octets of zeros. */
os_memset(imsk, 0, 32);
- res = eap_teap_tls_prf(s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, s_imck_msk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, sizeof(imck));
if (res < 0)
@@ -136,7 +142,8 @@
}
-int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -170,14 +177,16 @@
context[0] = 0;
context[1] = 0;
context[2] = 64;
- if (eap_teap_tls_prf(emsk, emsk_len, "TEAPbindkey@ietf.org",
+ if (eap_teap_tls_prf(tls_cs, emsk, emsk_len,
+ "TEAPbindkey@ietf.org",
context, sizeof(context), imsk, 64) < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
imsk, 32);
- res = eap_teap_tls_prf(prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs,
+ prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -207,7 +216,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
}
- res = eap_teap_tls_prf(prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -418,6 +427,17 @@
int tlv_type, u8 *pos, size_t len)
{
switch (tlv_type) {
+ case TEAP_TLV_IDENTITY_TYPE:
+ if (len < 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Identity-Type TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->identity_type = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Identity-Type: %u",
+ tlv->identity_type);
+ break;
case TEAP_TLV_RESULT:
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
if (tlv->result) {
@@ -452,6 +472,15 @@
tlv->nak = pos;
tlv->nak_len = len;
break;
+ case TEAP_TLV_ERROR:
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Too short Error TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->error_code = WPA_GET_BE32(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Error: %u", tlv->error_code);
+ break;
case TEAP_TLV_REQUEST_ACTION:
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
pos, len);
@@ -661,12 +690,29 @@
}
-int eap_teap_allowed_anon_prov_phase2_method(u8 type)
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + 2);
+ if (!buf)
+ return NULL;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Identity-Type TLV(Identity-Type=%d)", id);
+ wpabuf_put_be16(buf, TEAP_TLV_IDENTITY_TYPE);
+ wpabuf_put_be16(buf, 2);
+ wpabuf_put_be16(buf, id);
+ return buf;
+}
+
+
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type)
{
/* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
* provide key generation, and be resistant to dictionary attack.
* Section 3.8 also mentions requirement for using EMSK Compound MAC. */
- return type == EAP_TYPE_PWD || type == EAP_TYPE_EKE;
+ return vendor == EAP_VENDOR_IETF &&
+ (type == EAP_TYPE_PWD || type == EAP_TYPE_EKE);
}
diff --git a/src/eap_common/eap_teap_common.h b/src/eap_common/eap_teap_common.h
index 585ec7c..3a25879 100644
--- a/src/eap_common/eap_teap_common.h
+++ b/src/eap_common/eap_teap_common.h
@@ -151,6 +151,12 @@
TEAP_STATUS_FAILURE = 2
};
+/* Identity-Type values within Identity-Type TLV */
+enum teap_identity_types {
+ TEAP_IDENTITY_TYPE_USER = 1,
+ TEAP_IDENTITY_TYPE_MACHINE = 2,
+};
+
#define TEAP_TLV_MANDATORY 0x8000
#define TEAP_TLV_TYPE_MASK 0x3fff
@@ -188,6 +194,8 @@
size_t basic_auth_req_len;
u8 *basic_auth_resp;
size_t basic_auth_resp_len;
+ u32 error_code;
+ u16 identity_type;
};
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
@@ -195,10 +203,12 @@
void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
const struct wpabuf *data);
struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf);
-int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk);
-int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk);
-int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk);
-int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk);
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk);
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk,
+ u8 *cmk);
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -212,7 +222,9 @@
const char * eap_teap_tlv_type_str(enum teap_tlv_types type);
struct wpabuf * eap_teap_tlv_result(int status, int intermediate);
struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error);
-int eap_teap_allowed_anon_prov_phase2_method(u8 type);
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id);
+enum eap_type;
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type);
int eap_teap_allowed_anon_prov_cipher_suite(u16 cs);
#endif /* EAP_TEAP_H */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index ac15e0e..c78b214 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
/*
* EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -32,12 +32,13 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_MAX_AUTH_ROUNDS 100
+#define EAP_MAX_AUTH_ROUNDS_SHORT 50
#define EAP_CLIENT_TIMEOUT_DEFAULT 60
static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method);
+ enum eap_type method);
static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
static void eap_sm_processIdentity(struct eap_sm *sm,
const struct wpabuf *req);
@@ -260,10 +261,12 @@
*/
sm->ignore = 0;
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->prev_failure = 0;
sm->expected_failure = 0;
sm->reauthInit = FALSE;
sm->erp_seq = (u32) -1;
+ sm->use_machine_cred = 0;
}
@@ -276,6 +279,7 @@
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
/*
* RFC 4137 does not describe clearing of idleWhile here, but doing so
* allows the timer tick to be stopped more quickly when EAP is not in
@@ -309,6 +313,10 @@
/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
eap_sm_parseEapReq(sm, eapReqData);
sm->num_rounds++;
+ if (!eapReqData || wpabuf_len(eapReqData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
@@ -319,7 +327,7 @@
SM_STATE(EAP, GET_METHOD)
{
int reinit;
- EapType method;
+ enum eap_type method;
const struct eap_method *eap_method;
SM_ENTRY(EAP, GET_METHOD);
@@ -815,7 +823,8 @@
wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
erp->keyname_nai, erp->next_seq);
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
EAP_CODE_INITIATE, eap_id);
if (msg == NULL)
@@ -949,6 +958,8 @@
SM_ENTRY(EAP, SEND_RESPONSE);
wpabuf_free(sm->lastRespData);
if (sm->eapRespData) {
+ if (wpabuf_len(sm->eapRespData) >= 20)
+ sm->num_rounds_short = 0;
if (sm->workaround)
os_memcpy(sm->last_sha1, sm->req_sha1, 20);
sm->lastId = sm->reqId;
@@ -1341,6 +1352,14 @@
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) {
+ if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) {
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP: more than %d authentication rounds (short) - abort",
+ EAP_MAX_AUTH_ROUNDS_SHORT);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else {
/* Local transitions */
eap_peer_sm_step_local(sm);
@@ -1349,7 +1368,7 @@
static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method)
+ enum eap_type method)
{
if (!eap_allowed_method(sm, vendor, method)) {
wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
@@ -1595,13 +1614,13 @@
static int eap_sm_set_scard_pin(struct eap_sm *sm,
struct eap_peer_config *conf)
{
- if (scard_set_pin(sm->scard_ctx, conf->pin)) {
+ if (scard_set_pin(sm->scard_ctx, conf->cert.pin)) {
/*
* Make sure the same PIN is not tried again in order to avoid
* blocking SIM.
*/
- os_free(conf->pin);
- conf->pin = NULL;
+ os_free(conf->cert.pin);
+ conf->cert.pin = NULL;
wpa_printf(MSG_WARNING, "PIN validation failed");
eap_sm_request_pin(sm);
@@ -1657,6 +1676,11 @@
identity_len = config->anonymous_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
identity, identity_len);
+ } else if (sm->use_machine_cred) {
+ identity = config->machine_identity;
+ identity_len = config->machine_identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@@ -2600,6 +2624,8 @@
static int eap_allowed_phase2_type(int vendor, int type)
{
+ if (vendor == EAP_VENDOR_HOSTAP)
+ return 1;
if (vendor != EAP_VENDOR_IETF)
return 0;
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
@@ -2662,7 +2688,7 @@
if (eap_allowed_phase2_type(vendor, method)) {
if (vendor == EAP_VENDOR_IETF &&
method == EAP_TYPE_TLS && config &&
- config->private_key2 == NULL)
+ !config->phase2_cert.private_key)
continue;
buf[*count].vendor = vendor;
buf[*count].method = method;
@@ -2721,8 +2747,15 @@
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
+
+ if (sm->use_machine_cred) {
+ *len = config->machine_identity_len;
+ return config->machine_identity;
+ }
+
*len = config->identity_len;
return config->identity;
}
@@ -2732,14 +2765,24 @@
struct eap_peer_config *config)
{
char *name;
+ const u8 *password;
+ size_t password_len;
- if (config->password == NULL)
+ if (sm->use_machine_cred) {
+ password = config->machine_password;
+ password_len = config->machine_password_len;
+ } else {
+ password = config->password;
+ password_len = config->password_len;
+ }
+
+ if (!password)
return -1;
- name = os_zalloc(config->password_len + 1);
- if (name == NULL)
+ name = os_zalloc(password_len + 1);
+ if (!name)
return -1;
- os_memcpy(name, config->password, config->password_len);
+ os_memcpy(name, password, password_len);
ext_password_free(sm->ext_pw_buf);
sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
@@ -2758,16 +2801,25 @@
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
*len = wpabuf_len(sm->ext_pw_buf);
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ return config->machine_password;
+ }
+
*len = config->password_len;
return config->password;
}
@@ -2785,10 +2837,14 @@
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
if (hash)
@@ -2797,6 +2853,14 @@
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ if (hash)
+ *hash = !!(config->flags &
+ EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
+ return config->machine_password;
+ }
+
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 148c906..3238f74 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
/*
* EAP peer configuration data
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,68 +10,9 @@
#define EAP_CONFIG_H
/**
- * struct eap_peer_config - EAP peer configuration/credentials
+ * struct eap_peer_cert_config - EAP peer certificate configuration/credential
*/
-struct eap_peer_config {
- /**
- * identity - EAP Identity
- *
- * This field is used to set the real user identity or NAI (for
- * EAP-PSK/PAX/SAKE/GPSK).
- */
- u8 *identity;
-
- /**
- * identity_len - EAP Identity length
- */
- size_t identity_len;
-
- /**
- * anonymous_identity - Anonymous EAP Identity
- *
- * This field is used for unencrypted use with EAP types that support
- * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
- * real identity (identity field) only to the authentication server.
- *
- * If not set, the identity field will be used for both unencrypted and
- * protected fields.
- *
- * This field can also be used with EAP-SIM/AKA/AKA' to store the
- * pseudonym identity.
- */
- u8 *anonymous_identity;
-
- /**
- * anonymous_identity_len - Length of anonymous_identity
- */
- size_t anonymous_identity_len;
-
- u8 *imsi_identity;
- size_t imsi_identity_len;
-
- /**
- * password - Password string for EAP
- *
- * This field can include either the plaintext password (default
- * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
- * presentation of the password) if flags field has
- * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
- * only be used with authentication mechanism that use this hash as the
- * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
- * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
- *
- * In addition, this field is used to configure a pre-shared key for
- * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
- * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
- * PSK.
- */
- u8 *password;
-
- /**
- * password_len - Length of password field
- */
- size_t password_len;
-
+struct eap_peer_cert_config {
/**
* ca_cert - File path to CA certificate file (PEM/DER)
*
@@ -231,14 +172,6 @@
char *check_cert_subject;
/**
- * check_cert_subject2 - Constraint for server certificate subject fields
- *
- * This field is like check_cert_subject, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *check_cert_subject2;
-
- /**
* altsubject_match - Constraint for server certificate alt. subject
*
* Semicolon separated string of entries to be matched against the
@@ -299,115 +232,181 @@
char *domain_match;
/**
- * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
+ * pin - PIN for USIM, GSM SIM, and smartcards
*
- * This file can have one or more trusted CA certificates. If ca_cert2
- * and ca_path2 are not included, server certificate will not be
- * verified. This is insecure and a trusted CA certificate should
- * always be configured. Full path to the file should be used since
- * working directory may change when wpa_supplicant is run in the
- * background.
+ * This field is used to configure PIN for SIM and smartcards for
+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+ * smartcard is used for private key operations.
*
- * This field is like ca_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * If left out, this will be asked through control interface.
*/
- char *ca_cert2;
+ char *pin;
/**
- * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
+ * engine - Enable OpenSSL engine (e.g., for smartcard access)
*
- * This path may contain multiple CA certificates in OpenSSL format.
- * Common use for this is to point to system trusted CA list which is
- * often installed into directory like /etc/ssl/certs. If configured,
- * these certificates are added to the list of trusted CAs. ca_cert
- * may also be included in that case, but it is not required.
- *
- * This field is like ca_path, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *ca_path2;
+ int engine;
/**
- * client_cert2 - File path to client certificate file
+ * engine_id - Engine ID for OpenSSL engine
*
- * This field is like client_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+ * engine.
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *client_cert2;
+ char *engine_id;
+
/**
- * private_key2 - File path to client private key file
+ * key_id - Key ID for OpenSSL engine
*
- * This field is like private_key, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *private_key2;
+ char *key_id;
/**
- * private_key2_passwd - Password for private key file
+ * cert_id - Cert ID for OpenSSL engine
*
- * This field is like private_key_passwd, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if the certificate operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *private_key2_passwd;
+ char *cert_id;
/**
- * dh_file2 - File path to DH/DSA parameters file (in PEM format)
+ * ca_cert_id - CA Cert ID for OpenSSL engine
*
- * This field is like dh_file, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if the CA certificate for EAP-TLS is on a smartcard.
*/
- char *dh_file2;
+ char *ca_cert_id;
/**
- * subject_match2 - Constraint for server certificate subject
+ * ocsp - Whether to use/require OCSP to check server certificate
*
- * This field is like subject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * 0 = do not use OCSP stapling (TLS certificate status extension)
+ * 1 = try to use OCSP stapling, but not require response
+ * 2 = require valid OCSP stapling response
*/
- char *subject_match2;
+ int ocsp;
+};
+
+/**
+ * struct eap_peer_config - EAP peer configuration/credentials
+ */
+struct eap_peer_config {
+ /**
+ * identity - EAP Identity
+ *
+ * This field is used to set the real user identity or NAI (for
+ * EAP-PSK/PAX/SAKE/GPSK).
+ */
+ u8 *identity;
/**
- * altsubject_match2 - Constraint for server certificate alt. subject
- *
- * This field is like altsubject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * identity_len - EAP Identity length
*/
- char *altsubject_match2;
+ size_t identity_len;
/**
- * domain_suffix_match2 - Constraint for server domain name
+ * anonymous_identity - Anonymous EAP Identity
*
- * This field is like domain_suffix_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This field is used for unencrypted use with EAP types that support
+ * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
+ * real identity (identity field) only to the authentication server.
+ *
+ * If not set, the identity field will be used for both unencrypted and
+ * protected fields.
+ *
+ * This field can also be used with EAP-SIM/AKA/AKA' to store the
+ * pseudonym identity.
*/
- char *domain_suffix_match2;
+ u8 *anonymous_identity;
/**
- * domain_match2 - Constraint for server domain name
- *
- * This field is like domain_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * anonymous_identity_len - Length of anonymous_identity
*/
- char *domain_match2;
+ size_t anonymous_identity_len;
+
+ u8 *imsi_identity;
+ size_t imsi_identity_len;
+
+ /**
+ * machine_identity - EAP Identity for machine credential
+ *
+ * This field is used to set the machine identity or NAI for cases where
+ * and explicit machine credential (instead of or in addition to a user
+ * credential (from %identity) is needed.
+ */
+ u8 *machine_identity;
+
+ /**
+ * machine_identity_len - EAP Identity length for machine credential
+ */
+ size_t machine_identity_len;
+
+ /**
+ * password - Password string for EAP
+ *
+ * This field can include either the plaintext password (default
+ * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+ * presentation of the password) if flags field has
+ * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+ * only be used with authentication mechanism that use this hash as the
+ * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+ * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
+ *
+ * In addition, this field is used to configure a pre-shared key for
+ * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
+ * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
+ * PSK.
+ */
+ u8 *password;
+
+ /**
+ * password_len - Length of password field
+ */
+ size_t password_len;
+
+ /**
+ * machine_password - Password string for EAP machine credential
+ *
+ * This field is used when machine credential based on username/password
+ * is needed instead of a user credential (from %password). See
+ * %password for more details on the format.
+ */
+ u8 *machine_password;
+
+ /**
+ * machine_password_len - Length of machine credential password field
+ */
+ size_t machine_password_len;
+
+ /**
+ * cert - Certificate parameters for Phase 1
+ */
+ struct eap_peer_cert_config cert;
+
+ /**
+ * phase2_cert - Certificate parameters for Phase 2
+ *
+ * This is like cert, but used for Phase 2 (inside
+ * EAP-TTLS/PEAP/FAST/TEAP tunnel) authentication.
+ */
+ struct eap_peer_cert_config phase2_cert;
+
+ /**
+ * machine_cert - Certificate parameters for Phase 2 machine credential
+ *
+ * This is like cert, but used for Phase 2 (inside EAP-TEAP tunnel)
+ * authentication with machine credentials (while phase2_cert is used
+ * for user credentials).
+ */
+ struct eap_peer_cert_config machine_cert;
/**
* eap_methods - Allowed EAP methods
@@ -496,6 +495,13 @@
char *phase2;
/**
+ * machine_phase2 - Phase2 parameters for machine credentials
+ *
+ * See phase2 for more details.
+ */
+ char *machine_phase2;
+
+ /**
* pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
*
* This field is used to configure PC/SC smartcard interface.
@@ -507,123 +513,6 @@
char *pcsc;
/**
- * pin - PIN for USIM, GSM SIM, and smartcards
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin;
-
- /**
- * engine - Enable OpenSSL engine (e.g., for smartcard access)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- int engine;
-
- /**
- * engine_id - Engine ID for OpenSSL engine
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *engine_id;
-
- /**
- * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- int engine2;
-
-
- /**
- * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * This field is like pin2, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin2;
-
- /**
- * engine2_id - Engine ID for OpenSSL engine (Phase 2)
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine_id, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *engine2_id;
-
-
- /**
- * key_id - Key ID for OpenSSL engine
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key_id;
-
- /**
- * cert_id - Cert ID for OpenSSL engine
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert_id;
-
- /**
- * ca_cert_id - CA Cert ID for OpenSSL engine
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert_id;
-
- /**
- * key2_id - Key ID for OpenSSL engine (phase2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key2_id;
-
- /**
- * cert2_id - Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert2_id;
-
- /**
- * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert2_id;
-
- /**
* otp - One-time-password
*
* This field should not be set in configuration step. It is only used
@@ -751,6 +640,8 @@
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
+#define EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH BIT(2)
+#define EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD BIT(3)
/**
* flags - Network configuration flags (bitfield)
*
@@ -760,19 +651,14 @@
* instead of plaintext password
* bit 1 = password is stored in external storage; the value in the
* password field is the name of that external entry
+ * bit 2 = machine password is represented as a 16-byte NtPasswordHash
+ * value instead of plaintext password
+ * bit 3 = machine password is stored in external storage; the value in
+ * the password field is the name of that external entry
*/
u32 flags;
/**
- * ocsp - Whether to use/require OCSP to check server certificate
- *
- * 0 = do not use OCSP stapling (TLS certificate status extension)
- * 1 = try to use OCSP stapling, but not require response
- * 2 = require valid OCSP stapling response
- */
- int ocsp;
-
- /**
* external_sim_resp - Response from external SIM processing
*
* This field should not be set in configuration step. It is only used
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 94ce57d..0ed4a2b 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -162,7 +162,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@@ -364,22 +364,24 @@
}
-static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
+static int eap_fast_select_phase2_method(struct eap_fast_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
/* TODO: TNC with anonymous provisioning; need to require both
* completed MSCHAPv2 and TNC */
- if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
- wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
- "during unauthenticated provisioning; reject phase2"
- " type %d", type);
+ if (data->anon_provisioning &&
+ (vendor != EAP_VENDOR_IETF || type != EAP_TYPE_MSCHAPV2)) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated provisioning; reject phase2 type %u:%u",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
@@ -391,7 +393,7 @@
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -404,7 +406,9 @@
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
@@ -422,6 +426,8 @@
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-FAST: too short "
@@ -429,14 +435,27 @@
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
"deinitialize previous method");
data->phase2_method->deinit(sm, data->phase2_priv);
@@ -448,7 +467,7 @@
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_fast_select_phase2_method(data, *pos) < 0) {
+ eap_fast_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -459,8 +478,9 @@
if ((data->phase2_priv == NULL &&
eap_fast_init_phase2_method(sm, data) < 0) ||
data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
- "Phase 2 EAP method %d", *pos);
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 096f0f2..8f29d4a 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -72,7 +72,7 @@
/**
* method - EAP type number (EAP_TYPE_*)
*/
- EapType method;
+ enum eap_type method;
/**
* name - Name of the method (e.g., "TLS")
@@ -312,7 +312,7 @@
EAP_FAILURE
} EAP_state;
/* Long-term local variables */
- EapType selectedMethod;
+ enum eap_type selectedMethod;
EapMethodState methodState;
int lastId;
struct wpabuf *lastRespData;
@@ -322,7 +322,7 @@
Boolean rxSuccess;
Boolean rxFailure;
int reqId;
- EapType reqMethod;
+ enum eap_type reqMethod;
int reqVendor;
u32 reqVendorMethod;
Boolean ignore;
@@ -366,6 +366,7 @@
u8 *peer_challenge, *auth_challenge;
int num_rounds;
+ int num_rounds_short;
int force_disabled;
struct wps_context *wps;
@@ -381,6 +382,7 @@
unsigned int expected_failure:1;
unsigned int ext_cert_check:1;
unsigned int waiting_ext_cert_check:1;
+ unsigned int use_machine_cred:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 9747954..f2d2947 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -27,7 +27,8 @@
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -47,7 +48,7 @@
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_peer_get_type(const char *name, int *vendor)
+enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -70,7 +71,7 @@
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_get_name(int vendor, EapType type)
+const char * eap_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
@@ -169,7 +170,7 @@
for (m = eap_methods; m; m = m->next)
c++;
-
+
*count = c;
return eap_methods;
}
@@ -279,7 +280,8 @@
* is not needed anymore.
*/
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index 09e08d3..e94f3d7 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -11,31 +11,33 @@
#include "eap_common/eap_defs.h"
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method);
const struct eap_method * eap_peer_get_methods(size_t *count);
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_peer_method_register(struct eap_method *method);
#ifdef IEEE8021X_EAPOL
-EapType eap_peer_get_type(const char *name, int *vendor);
-const char * eap_get_name(int vendor, EapType type);
+enum eap_type eap_peer_get_type(const char *name, int *vendor);
+const char * eap_get_name(int vendor, enum eap_type type);
size_t eap_get_names(char *buf, size_t buflen);
char ** eap_get_names_as_string_array(size_t *num);
void eap_peer_unregister_methods(void);
#else /* IEEE8021X_EAPOL */
-static inline EapType eap_peer_get_type(const char *name, int *vendor)
+static inline enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
*vendor = EAP_VENDOR_IETF;
return EAP_TYPE_NONE;
}
-static inline const char * eap_get_name(int vendor, EapType type)
+static inline const char * eap_get_name(int vendor, enum eap_type type)
{
return NULL;
}
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 6453afe..92b15ec 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -148,7 +148,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_peap_deinit(sm, data);
return NULL;
}
@@ -603,6 +603,8 @@
u8 *pos;
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
+ int vendor;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-PEAP: too short "
@@ -666,13 +668,26 @@
#endif /* EAP_TNC */
/* fall through */
default:
+ vendor = EAP_VENDOR_IETF;
+ method = *pos;
+
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE) {
size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor !=
- EAP_VENDOR_IETF ||
- data->phase2_types[i].method != *pos)
+ if (data->phase2_types[i].vendor != vendor ||
+ data->phase2_types[i].method != method)
continue;
data->phase2_type.vendor =
@@ -686,8 +701,9 @@
break;
}
}
- if (*pos != data->phase2_type.method ||
- *pos == EAP_TYPE_NONE) {
+ if (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 6cd72e0..54f102a 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -30,6 +30,7 @@
u8 *password;
size_t password_len;
int password_hash;
+ struct wpa_freq_range_list allowed_groups;
u16 group_num;
u8 prep;
u8 token[4];
@@ -54,6 +55,9 @@
};
+static void eap_pwd_deinit(struct eap_sm *sm, void *priv);
+
+
#ifndef CONFIG_NO_STDOUT_DEBUG
static const char * eap_pwd_state_txt(int state)
{
@@ -92,6 +96,7 @@
size_t identity_len, password_len;
int fragment_size;
int pwhash;
+ const char *phase1;
password = eap_get_config_password2(sm, &password_len, &pwhash);
if (password == NULL) {
@@ -129,6 +134,30 @@
data->password_len = password_len;
data->password_hash = pwhash;
+ phase1 = eap_get_config_phase1(sm);
+ if (phase1) {
+ const char *pos, *end;
+ char *copy = NULL;
+ int res;
+
+ pos = os_strstr(phase1, "eap_pwd_groups=");
+ if (pos) {
+ pos += 15;
+ end = os_strchr(pos, ' ');
+ if (end) {
+ copy = os_zalloc(end - pos + 1);
+ if (!copy)
+ goto fail;
+ os_memcpy(copy, pos, end - pos);
+ pos = copy;
+ }
+ res = freq_range_list_parse(&data->allowed_groups, pos);
+ os_free(copy);
+ if (res)
+ goto fail;
+ }
+ }
+
data->out_frag_pos = data->in_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
fragment_size = eap_get_config_fragment_size(sm);
@@ -140,6 +169,9 @@
data->state = PWD_ID_Req;
return data;
+fail:
+ eap_pwd_deinit(sm, data);
+ return NULL;
}
@@ -163,6 +195,7 @@
}
wpabuf_free(data->inbuf);
wpabuf_free(data->outbuf);
+ os_free(data->allowed_groups.range);
bin_clear_free(data, sizeof(*data));
}
@@ -203,6 +236,18 @@
}
+static int eap_pwd_allowed_group(struct eap_pwd_data *data, u16 group)
+{
+ if (!data->allowed_groups.range) {
+ /* By default, allow the groups using NIST curves P-256, P-384,
+ * and P-521. */
+ return group == 19 || group == 20 || group == 21;
+ }
+
+ return freq_range_list_includes(&data->allowed_groups, group);
+}
+
+
static void
eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_method_ret *ret,
@@ -228,9 +273,11 @@
wpa_printf(MSG_DEBUG,
"EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u",
data->group_num, id->random_function, id->prf, id->prep);
- if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
- (id->prf != EAP_PWD_DEFAULT_PRF)) {
- ret->ignore = TRUE;
+ if (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC ||
+ id->prf != EAP_PWD_DEFAULT_PRF ||
+ !eap_pwd_allowed_group(data, data->group_num)) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unsupported or disabled proposal");
eap_pwd_state(data, FAILURE);
return;
}
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index eea7d6e..f751fbe 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -35,7 +35,9 @@
void *phase2_priv;
int phase2_success;
int inner_method_done;
+ int iresult_verified;
int result_success_done;
+ int on_tx_completion;
struct eap_method_type phase2_type;
struct eap_method_type *phase2_types;
@@ -167,7 +169,7 @@
eap_teap_parse_phase1(data, config->phase1);
if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) &&
- !config->ca_cert && !config->ca_path) {
+ !config->cert.ca_cert && !config->cert.ca_path) {
/* Prevent PAC provisioning without mutual authentication
* (either by validating server certificate or by suitable
* inner EAP method). */
@@ -178,7 +180,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_teap_deinit(sm, data);
return NULL;
}
@@ -276,8 +278,10 @@
{
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_msk(data->simck_msk, data->key_data) < 0 ||
- eap_teap_derive_eap_emsk(data->simck_msk, data->emsk) < 0)
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ data->key_data) < 0 ||
+ eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ data->emsk) < 0)
return -1;
data->success = 1;
return 0;
@@ -308,6 +312,7 @@
struct eap_teap_data *data)
{
data->inner_method_done = 0;
+ data->iresult_verified = 0;
data->phase2_method =
eap_peer_get_eap_method(data->phase2_type.vendor,
data->phase2_type.method);
@@ -322,7 +327,8 @@
}
-static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
+static int eap_teap_select_phase2_method(struct eap_teap_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
@@ -330,15 +336,15 @@
* completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */
if (data->anon_provisioning &&
- !eap_teap_allowed_anon_prov_phase2_method(type)) {
+ !eap_teap_allowed_anon_prov_phase2_method(vendor, type)) {
wpa_printf(MSG_INFO,
- "EAP-TEAP: EAP type %u not allowed during unauthenticated provisioning",
- type);
+ "EAP-TEAP: EAP type %u:%u not allowed during unauthenticated provisioning",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG,
@@ -350,7 +356,7 @@
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -363,13 +369,31 @@
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
}
+static void eap_teap_deinit_inner_eap(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ if (!data->phase2_priv || !data->phase2_method)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
+}
+
+
static int eap_teap_phase2_request(struct eap_sm *sm,
struct eap_teap_data *data,
struct eap_method_ret *ret,
@@ -381,6 +405,8 @@
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO,
@@ -389,26 +415,33 @@
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
+ eap_teap_deinit_inner_eap(sm, data);
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
- data->phase2_method->deinit(sm, data->phase2_priv);
- data->phase2_method = NULL;
- data->phase2_priv = NULL;
- data->phase2_type.vendor = EAP_VENDOR_IETF;
- data->phase2_type.method = EAP_TYPE_NONE;
- }
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method))
+ eap_teap_deinit_inner_eap(sm, data);
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_teap_select_phase2_method(data, *pos) < 0) {
+ eap_teap_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -419,8 +452,8 @@
if ((!data->phase2_priv && eap_teap_init_phase2_method(sm, data) < 0) ||
!data->phase2_method) {
wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to initialize Phase 2 EAP method %d",
- *pos);
+ "EAP-TEAP: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
@@ -435,7 +468,8 @@
if (!(*resp) ||
(iret.methodState == METHOD_DONE &&
iret.decision == DECISION_FAIL)) {
- ret->methodState = METHOD_DONE;
+ /* Wait for protected indication of failure */
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
} else if ((iret.methodState == METHOD_DONE ||
iret.methodState == METHOD_MAY_CONT) &&
@@ -499,10 +533,23 @@
}
+static struct wpabuf * eap_teap_add_identity_type(struct eap_sm *sm,
+ struct wpabuf *msg)
+{
+ struct wpabuf *tlv;
+
+ tlv = eap_teap_tlv_identity_type(sm->use_machine_cred ?
+ TEAP_IDENTITY_TYPE_MACHINE :
+ TEAP_IDENTITY_TYPE_USER);
+ return wpabuf_concat(msg, tlv);
+}
+
+
static struct wpabuf * eap_teap_process_eap_payload_tlv(
struct eap_sm *sm, struct eap_teap_data *data,
struct eap_method_ret *ret,
- u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
+ u8 *eap_payload_tlv, size_t eap_payload_tlv_len,
+ enum teap_identity_types req_id_type)
{
struct eap_hdr *hdr;
struct wpabuf *resp = NULL;
@@ -534,13 +581,18 @@
return NULL;
}
- return eap_teap_tlv_eap_payload(resp);
+ resp = eap_teap_tlv_eap_payload(resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
+
+ return resp;
}
static struct wpabuf * eap_teap_process_basic_auth_req(
struct eap_sm *sm, struct eap_teap_data *data,
- u8 *basic_auth_req, size_t basic_auth_req_len)
+ u8 *basic_auth_req, size_t basic_auth_req_len,
+ enum teap_identity_types req_id_type)
{
const u8 *identity, *password;
size_t identity_len, password_len, plen;
@@ -570,6 +622,8 @@
wpabuf_put_data(resp, password, password_len);
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Resp",
resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
/* Assume this succeeds so that Result TLV(Success) from the server can
* be used to terminate TEAP. */
@@ -679,7 +733,8 @@
data->simck_idx + 1);
if (!data->phase2_method)
- return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
cmk_msk);
if (!data->phase2_method || !data->phase2_priv) {
@@ -711,7 +766,8 @@
&emsk_len);
}
- res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
msk, msk_len, emsk, emsk_len,
data->simck_msk, cmk_msk,
data->simck_emsk, cmk_emsk);
@@ -1188,6 +1244,7 @@
struct eap_teap_tlv_parse tlv;
int failed = 0;
enum teap_error_codes error = 0;
+ int iresult_added = 0;
if (eap_teap_parse_decrypted(decrypted, &tlv, &resp) < 0) {
/* Parsing failed - no response available */
@@ -1211,14 +1268,21 @@
goto send_resp;
}
- if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
- (!data->result_success_done &&
- tlv.result == TEAP_STATUS_SUCCESS)) &&
- !tlv.crypto_binding) {
- /* Result TLV or Intermediate-Result TLV indicating success,
- * but no Crypto-Binding TLV */
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Intermediate-Result TLV indicating success, but no
+ * Crypto-Binding TLV */
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Result TLV or Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ "EAP-TEAP: Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ goto done;
+ }
+
+ if (!data->iresult_verified && !data->result_success_done &&
+ tlv.result == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Result TLV indicating success, but no Crypto-Binding TLV */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Result TLV indicating success, but no Crypto-Binding TLV");
failed = 1;
error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
goto done;
@@ -1234,17 +1298,45 @@
goto done;
}
+ if (tlv.identity_type == TEAP_IDENTITY_TYPE_MACHINE) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ sm->use_machine_cred = config && config->machine_identity &&
+ config->machine_identity_len;
+ } else if (tlv.identity_type) {
+ sm->use_machine_cred = 0;
+ }
+ if (tlv.identity_type) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ os_free(data->phase2_types);
+ data->phase2_types = NULL;
+ data->num_phase2_types = 0;
+ if (config &&
+ eap_peer_select_phase2_methods(config, "auth=",
+ &data->phase2_types,
+ &data->num_phase2_types,
+ sm->use_machine_cred) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to update Phase 2 EAP types");
+ failed = 1;
+ goto done;
+ }
+ }
+
if (tlv.basic_auth_req) {
tmp = eap_teap_process_basic_auth_req(sm, data,
tlv.basic_auth_req,
- tlv.basic_auth_req_len);
+ tlv.basic_auth_req_len,
+ tlv.identity_type);
if (!tmp)
failed = 1;
resp = wpabuf_concat(resp, tmp);
} else if (tlv.eap_payload_tlv) {
tmp = eap_teap_process_eap_payload_tlv(sm, data, ret,
tlv.eap_payload_tlv,
- tlv.eap_payload_tlv_len);
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
if (!tmp)
failed = 1;
resp = wpabuf_concat(resp, tmp);
@@ -1257,6 +1349,7 @@
resp = wpabuf_concat(resp, tmp);
if (tlv.iresult == TEAP_STATUS_FAILURE)
failed = 1;
+ iresult_added = 1;
}
}
@@ -1280,8 +1373,10 @@
resp = wpabuf_concat(resp, tmp);
if (tlv.result == TEAP_STATUS_SUCCESS && !failed)
data->result_success_done = 1;
- if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed)
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) {
data->inner_method_done = 0;
+ data->iresult_verified = 1;
+ }
}
}
@@ -1315,6 +1410,7 @@
data->phase2_method->vendor == 0 &&
eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) &&
eap_teap_allowed_anon_prov_phase2_method(
+ data->phase2_method->vendor,
data->phase2_method->method))) &&
(tlv.iresult == TEAP_STATUS_SUCCESS ||
tlv.result == TEAP_STATUS_SUCCESS)) {
@@ -1343,13 +1439,22 @@
tmp = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
resp = wpabuf_concat(tmp, resp);
}
+ if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
+ tlv.iresult == TEAP_STATUS_FAILURE) && !iresult_added) {
+ tmp = eap_teap_tlv_result((!failed && data->phase2_success) ?
+ TEAP_STATUS_SUCCESS :
+ TEAP_STATUS_FAILURE, 1);
+ resp = wpabuf_concat(tmp, resp);
+ }
if (resp && tlv.result == TEAP_STATUS_SUCCESS && !failed &&
- tlv.crypto_binding && data->phase2_success) {
+ (tlv.crypto_binding || data->iresult_verified) &&
+ data->phase2_success) {
/* Successfully completed Phase 2 */
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Authentication completed successfully");
- ret->methodState = data->provisioning ?
+ ret->methodState = METHOD_MAY_CONT;
+ data->on_tx_completion = data->provisioning ?
METHOD_MAY_CONT : METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
}
@@ -1402,9 +1507,18 @@
if (wpabuf_len(in_data) == 0) {
/* Received TLS ACK - requesting more fragments */
- return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
- data->teap_version,
- identifier, NULL, out_data);
+ res = eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
+ data->teap_version,
+ identifier, NULL, out_data);
+ if (res == 0 && !data->ssl.tls_out &&
+ data->on_tx_completion) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Mark authentication completed at full TX of fragments");
+ ret->methodState = data->on_tx_completion;
+ data->on_tx_completion = 0;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+ return res;
}
res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
@@ -1904,6 +2018,8 @@
data->phase2_success = 0;
data->inner_method_done = 0;
data->result_success_done = 0;
+ data->iresult_verified = 0;
+ data->done_on_tx_completion = 0;
data->resuming = 1;
data->provisioning = 0;
data->anon_provisioning = 0;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 15d60d7..d9771f6 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -33,10 +33,17 @@
{
struct eap_tls_data *data;
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL ||
- ((sm->init_phase2 ? config->private_key2 : config->private_key)
- == NULL &&
- (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
+ struct eap_peer_cert_config *cert;
+
+ if (!config)
+ return NULL;
+ if (!sm->init_phase2)
+ cert = &config->cert;
+ else if (sm->use_machine_cred)
+ cert = &config->machine_cert;
+ else
+ cert = &config->phase2_cert;
+ if (!cert->private_key && cert->engine == 0) {
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
return NULL;
}
@@ -51,13 +58,12 @@
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
- if (config->engine) {
+ if (cert->engine) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
"PIN");
eap_sm_request_pin(sm);
sm->ignore = TRUE;
- } else if (config->private_key && !config->private_key_passwd)
- {
+ } else if (cert->private_key && !cert->private_key_passwd) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
"key passphrase");
eap_sm_request_passphrase(sm);
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 7e0690c..80e2d71 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -16,7 +16,7 @@
#include "eap_config.h"
-static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+static struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -105,8 +105,8 @@
}
-static void eap_tls_params_from_conf1(struct tls_connection_params *params,
- struct eap_peer_config *config)
+static void eap_tls_cert_params_from_conf(struct tls_connection_params *params,
+ struct eap_peer_cert_config *config)
{
params->ca_cert = config->ca_cert;
params->ca_path = config->ca_path;
@@ -125,6 +125,19 @@
params->key_id = config->key_id;
params->cert_id = config->cert_id;
params->ca_cert_id = config->ca_cert_id;
+ if (config->ocsp)
+ params->flags |= TLS_CONN_REQUEST_OCSP;
+ if (config->ocsp >= 2)
+ params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
+}
+
+
+static void eap_tls_params_from_conf1(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->cert);
eap_tls_params_flags(params, config->phase1);
}
@@ -132,27 +145,19 @@
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = config->ca_cert2;
- params->ca_path = config->ca_path2;
- params->client_cert = config->client_cert2;
- params->private_key = config->private_key2;
- params->private_key_passwd = config->private_key2_passwd;
- params->dh_file = config->dh_file2;
- params->subject_match = config->subject_match2;
- params->altsubject_match = config->altsubject_match2;
- params->check_cert_subject = config->check_cert_subject2;
- params->suffix_match = config->domain_suffix_match2;
- params->domain_match = config->domain_match2;
- params->engine = config->engine2;
- params->engine_id = config->engine2_id;
- params->pin = config->pin2;
- params->key_id = config->key2_id;
- params->cert_id = config->cert2_id;
- params->ca_cert_id = config->ca_cert2_id;
+ eap_tls_cert_params_from_conf(params, &config->phase2_cert);
eap_tls_params_flags(params, config->phase2);
}
+static void eap_tls_params_from_conf2m(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->machine_cert);
+ eap_tls_params_flags(params, config->machine_phase2);
+}
+
+
static int eap_tls_params_from_conf(struct eap_sm *sm,
struct eap_ssl_data *data,
struct tls_connection_params *params,
@@ -199,7 +204,10 @@
*/
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
- if (phase2) {
+ if (phase2 && sm->use_machine_cred) {
+ wpa_printf(MSG_DEBUG, "TLS: using machine config options");
+ eap_tls_params_from_conf2m(params, config);
+ } else if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
} else {
@@ -242,12 +250,6 @@
{
int res;
- if (config->ocsp)
- params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp >= 2)
- params->flags |= TLS_CONN_REQUIRE_OCSP;
- if (config->ocsp == 3)
- params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@@ -264,8 +266,8 @@
*/
wpa_printf(MSG_INFO,
"TLS: Bad PIN provided, requesting a new one");
- os_free(config->pin);
- config->pin = NULL;
+ os_free(config->cert.pin);
+ config->cert.pin = NULL;
eap_sm_request_pin(sm);
sm->ignore = TRUE;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
@@ -619,7 +621,8 @@
* @out_data: Buffer for returning the allocated output buffer
* Returns: ret (0 or 1) on success, -1 on failure
*/
-static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
+static int eap_tls_process_output(struct eap_ssl_data *data,
+ enum eap_type eap_type,
int peap_version, u8 id, int ret,
struct wpabuf **out_data)
{
@@ -717,7 +720,7 @@
* the tunneled data is used.
*/
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -809,7 +812,7 @@
* @peap_version: Version number for EAP-PEAP/TTLS
* Returns: Pointer to the allocated ACK frame or %NULL on failure
*/
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version)
{
struct wpabuf *resp;
@@ -899,7 +902,7 @@
*/
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags)
@@ -1056,7 +1059,7 @@
* Returns: 0 on success, -1 on failure
*/
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -1092,17 +1095,21 @@
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types)
+ size_t *num_types, int use_machine_cred)
{
char *start, *pos, *buf;
struct eap_method_type *methods = NULL, *_methods;
u32 method;
size_t num_methods = 0, prefix_len;
+ const char *phase2;
- if (config == NULL || config->phase2 == NULL)
+ if (!config)
+ goto get_defaults;
+ phase2 = use_machine_cred ? config->machine_phase2 : config->phase2;
+ if (!phase2)
goto get_defaults;
- start = buf = os_strdup(config->phase2);
+ start = buf = os_strdup(phase2);
if (buf == NULL)
return -1;
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index d96eff1..183b7de 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -107,17 +107,17 @@
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data);
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version);
int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
char *buf, size_t buflen, int verbose);
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags);
@@ -127,13 +127,13 @@
const struct wpabuf *in_data,
struct wpabuf **in_decrypted);
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data);
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types);
+ size_t *num_types, int use_machine_cred);
int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
struct eap_hdr *hdr, struct wpabuf **resp);
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 1c8dbe2..662676f 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -146,8 +146,8 @@
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
if (eap_peer_select_phase2_methods(config, "autheap=",
&data->phase2_eap_types,
- &data->num_phase2_eap_types)
- < 0) {
+ &data->num_phase2_eap_types,
+ 0) < 0) {
eap_ttls_deinit(sm, data);
return NULL;
}
@@ -311,11 +311,11 @@
static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
- u8 method)
+ int vendor, enum eap_type method)
{
size_t i;
for (i = 0; i < data->num_phase2_eap_types; i++) {
- if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_eap_types[i].vendor != vendor ||
data->phase2_eap_types[i].method != method)
continue;
@@ -362,17 +362,19 @@
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *hdr, size_t len,
- u8 method, struct wpabuf **resp)
+ int vendor, enum eap_type method,
+ struct wpabuf **resp)
{
#ifdef EAP_TNC
if (data->tnc_started && data->phase2_method &&
- data->phase2_priv && method == EAP_TYPE_TNC &&
+ data->phase2_priv &&
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC &&
data->phase2_eap_type.method == EAP_TYPE_TNC)
return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
resp);
if (data->ready_for_tnc && !data->tnc_started &&
- method == EAP_TYPE_TNC) {
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
"EAP method");
data->tnc_started = 1;
@@ -386,7 +388,7 @@
return -1;
}
- data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_eap_type.vendor = vendor;
data->phase2_eap_type.method = method;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
"Phase 2 EAP vendor %d method %d (TNC)",
@@ -400,10 +402,11 @@
if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
data->phase2_eap_type.method == EAP_TYPE_NONE)
- eap_ttls_phase2_select_eap_method(data, method);
+ eap_ttls_phase2_select_eap_method(data, vendor, method);
- if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
- {
+ if (vendor != data->phase2_eap_type.vendor ||
+ method != data->phase2_eap_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
data->num_phase2_eap_types,
hdr, resp))
@@ -412,8 +415,7 @@
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_peer_get_eap_method(
- EAP_VENDOR_IETF, method);
+ data->phase2_method = eap_peer_get_eap_method(vendor, method);
if (data->phase2_method) {
sm->init_phase2 = 1;
data->phase2_priv = data->phase2_method->init(sm);
@@ -421,8 +423,9 @@
}
}
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
- "Phase 2 EAP method %d", method);
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
return -1;
}
@@ -451,9 +454,23 @@
case EAP_TYPE_IDENTITY:
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
break;
+ case EAP_TYPE_EXPANDED:
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
+ WPA_GET_BE24(pos + 1),
+ WPA_GET_BE32(pos + 4),
+ resp) < 0)
+ return -1;
+ break;
default:
if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
- *pos, resp) < 0)
+ EAP_VENDOR_IETF, *pos,
+ resp) < 0)
return -1;
break;
}
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index a32c883..540b4e7 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -108,37 +108,162 @@
};
struct eap_config {
+ /**
+ * ssl_ctx - TLS context
+ *
+ * This is passed to the EAP server implementation as a callback
+ * context for TLS operations.
+ */
void *ssl_ctx;
void *msg_ctx;
+
+ /**
+ * eap_sim_db_priv - EAP-SIM/AKA database context
+ *
+ * This is passed to the EAP-SIM/AKA server implementation as a
+ * callback context.
+ */
void *eap_sim_db_priv;
Boolean backend_auth;
int eap_server;
+
+ /**
+ * pwd_group - The D-H group assigned for EAP-pwd
+ *
+ * If EAP-pwd is not used it can be set to zero.
+ */
u16 pwd_group;
+
+ /**
+ * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
+ *
+ * This parameter is used to set a key for EAP-FAST to encrypt the
+ * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
+ * set, must point to a 16-octet key.
+ */
u8 *pac_opaque_encr_key;
+
+ /**
+ * eap_fast_a_id - EAP-FAST authority identity (A-ID)
+ *
+ * If EAP-FAST is not used, this can be set to %NULL. In theory, this
+ * is a variable length field, but due to some existing implementations
+ * requiring A-ID to be 16 octets in length, it is recommended to use
+ * that length for the field to provide interoperability with deployed
+ * peer implementations.
+ */
u8 *eap_fast_a_id;
+
+ /**
+ * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
+ */
size_t eap_fast_a_id_len;
+ /**
+ * eap_fast_a_id_info - EAP-FAST authority identifier information
+ *
+ * This A-ID-Info contains a user-friendly name for the A-ID. For
+ * example, this could be the enterprise and server names in
+ * human-readable format. This field is encoded as UTF-8. If EAP-FAST
+ * is not used, this can be set to %NULL.
+ */
char *eap_fast_a_id_info;
- int eap_fast_prov;
+
+ /**
+ * eap_fast_prov - EAP-FAST provisioning modes
+ *
+ * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
+ * 2 = only authenticated provisioning allowed, 3 = both provisioning
+ * modes allowed.
+ */
+ enum {
+ NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
+ } eap_fast_prov;
+
+ /**
+ * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
+ *
+ * This is the hard limit on how long a provisioned PAC-Key can be
+ * used.
+ */
int pac_key_lifetime;
+
+ /**
+ * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
+ *
+ * This is a soft limit on the PAC-Key. The server will automatically
+ * generate a new PAC-Key when this number of seconds (or fewer) of the
+ * lifetime remains.
+ */
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ enum eap_teap_id {
+ EAP_TEAP_ID_ALLOW_ANY = 0,
+ EAP_TEAP_ID_REQUIRE_USER = 1,
+ EAP_TEAP_ID_REQUIRE_MACHINE = 2,
+ EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3,
+ EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4,
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5,
+ } eap_teap_id;
+
+ /**
+ * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
+ *
+ * This controls whether the protected success/failure indication
+ * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
+ */
int eap_sim_aka_result_ind;
+ int eap_sim_id;
+
+ /**
+ * tnc - Trusted Network Connect (TNC)
+ *
+ * This controls whether TNC is enabled and will be required before the
+ * peer is allowed to connect. Note: This is only used with EAP-TTLS
+ * and EAP-FAST. If any other EAP method is enabled, the peer will be
+ * allowed to connect without TNC.
+ */
int tnc;
+
+ /**
+ * wps - Wi-Fi Protected Setup context
+ *
+ * If WPS is used with an external RADIUS server (which is quite
+ * unlikely configuration), this is used to provide a pointer to WPS
+ * context data. Normally, this can be set to %NULL.
+ */
struct wps_context *wps;
- const struct wpabuf *assoc_wps_ie;
- const struct wpabuf *assoc_p2p_ie;
- const u8 *peer_addr;
int fragment_size;
int pbc_in_m1;
- const u8 *server_id;
+ /**
+ * server_id - Server identity
+ */
+ u8 *server_id;
size_t server_id_len;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
int erp;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
+};
+
+struct eap_session_data {
+ const struct wpabuf *assoc_wps_ie;
+ const struct wpabuf *assoc_p2p_ie;
+ const u8 *peer_addr;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -147,7 +272,8 @@
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *eap_conf);
+ const struct eap_config *conf,
+ const struct eap_session_data *sess);
void eap_server_sm_deinit(struct eap_sm *sm);
int eap_server_sm_step(struct eap_sm *sm);
void eap_sm_notify_cached(struct eap_sm *sm);
@@ -164,5 +290,6 @@
const u8 *challenge, const u8 *response);
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
void eap_user_free(struct eap_user *user);
+void eap_server_config_free(struct eap_config *cfg);
#endif /* EAP_H */
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 8e6ac46..44896a6 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -23,7 +23,7 @@
*/
struct eap_method {
int vendor;
- EapType method;
+ enum eap_type method;
const char *name;
void * (*init)(struct eap_sm *sm);
@@ -128,7 +128,7 @@
/* Full authenticator state machine local variables */
/* Long-term (maintained between packets) */
- EapType currentMethod;
+ enum eap_type currentMethod;
int currentId;
enum {
METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
@@ -141,7 +141,7 @@
Boolean rxResp;
Boolean rxInitiate;
int respId;
- EapType respMethod;
+ enum eap_type respMethod;
int respVendor;
u32 respVendorMethod;
Boolean ignore;
@@ -154,7 +154,7 @@
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
Boolean changed;
- void *eapol_ctx, *msg_ctx;
+ void *eapol_ctx;
const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
u8 *identity;
@@ -167,13 +167,12 @@
struct eap_user *user;
int user_eap_method_index;
int init_phase2;
- void *ssl_ctx;
- struct eap_sim_db_data *eap_sim_db_priv;
- Boolean backend_auth;
+ const struct eap_config *cfg;
+ struct eap_config cfg_buf;
Boolean update_user;
- int eap_server;
- int num_rounds;
+ unsigned int num_rounds;
+ unsigned int num_rounds_short;
enum {
METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
} method_pending;
@@ -181,21 +180,6 @@
u8 *auth_challenge;
u8 *peer_challenge;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- enum {
- NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
- } eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
- int eap_sim_aka_result_ind;
- int tnc;
- u16 pwd_group;
- struct wps_context *wps;
struct wpabuf *assoc_wps_ie;
struct wpabuf *assoc_p2p_ie;
@@ -203,19 +187,8 @@
u8 peer_addr[ETH_ALEN];
- /* Fragmentation size for EAP method init() handler */
- int fragment_size;
-
- int pbc_in_m1;
-
- const u8 *server_id;
- size_t server_id_len;
-
Boolean initiate_reauth_start_sent;
Boolean try_initiate_reauth;
- int erp;
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index fdbea7a..ad60700 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -12,14 +12,15 @@
#include "eap_common/eap_defs.h"
const struct eap_method * eap_server_get_eap_method(int vendor,
- EapType method);
+ enum eap_type method);
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_server_method_register(struct eap_method *method);
-EapType eap_server_get_type(const char *name, int *vendor);
+enum eap_type eap_server_get_type(const char *name, int *vendor);
void eap_server_unregister_methods(void);
-const char * eap_server_get_name(int vendor, EapType type);
+const char * eap_server_get_name(int vendor, enum eap_type type);
/* EAP server method registration calls for statically linked in methods */
int eap_server_identity_register(void);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 724ec15..34ce239 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -23,8 +23,6 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
-
/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
@@ -37,9 +35,10 @@
static int eap_sm_nextId(struct eap_sm *sm, int id);
static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm,
+ int *vendor);
static int eap_sm_Policy_getDecision(struct eap_sm *sm);
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method);
static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
@@ -94,7 +93,7 @@
}
msg = eap_msg_alloc(EAP_VENDOR_IETF,
- (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH_START, plen,
EAP_CODE_INITIATE, id);
if (msg == NULL)
return NULL;
@@ -215,6 +214,7 @@
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
}
@@ -222,7 +222,7 @@
{
SM_ENTRY(EAP, INITIALIZE);
- if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+ if (sm->eap_if.eapRestart && !sm->cfg->eap_server && sm->identity) {
/*
* Need to allow internal Identity method to be used instead
* of passthrough at the beginning of reauthentication.
@@ -256,7 +256,7 @@
sm->m = NULL;
sm->user_eap_method_index = 0;
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
sm->currentMethod = EAP_TYPE_NONE;
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
@@ -265,9 +265,10 @@
}
}
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->method_pending = METHOD_PENDING_NONE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -299,7 +300,7 @@
}
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"method=%u", sm->currentMethod);
}
@@ -324,7 +325,7 @@
sm->eap_if.eapReq = TRUE;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -336,6 +337,10 @@
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
sm->num_rounds++;
+ if (!sm->eap_if.eapRespData || wpabuf_len(sm->eap_if.eapRespData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
@@ -353,6 +358,8 @@
sm->retransCount = 0;
if (sm->eap_if.eapReqData) {
+ if (wpabuf_len(sm->eap_if.eapReqData) >= 20)
+ sm->num_rounds_short = 0;
if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
{
sm->eap_if.eapResp = FALSE;
@@ -529,7 +536,7 @@
sm->eap_if.eapSessionId,
sm->eap_if.eapSessionIdLen);
}
- if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ if (sm->cfg->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
@@ -541,7 +548,7 @@
SM_STATE(EAP, PROPOSE_METHOD)
{
int vendor;
- EapType type;
+ enum eap_type type;
SM_ENTRY(EAP, PROPOSE_METHOD);
@@ -579,7 +586,7 @@
else
sm->methodState = METHOD_PROPOSED;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", vendor, sm->currentMethod);
eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
vendor, sm->currentMethod);
@@ -635,8 +642,8 @@
sm->eap_if.eapTimeout = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR, MAC2STR(sm->peer_addr));
}
@@ -650,7 +657,7 @@
sm->lastReqData = NULL;
sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -667,7 +674,7 @@
sm->eap_if.eapKeyAvailable = TRUE;
sm->eap_if.eapSuccess = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -720,7 +727,8 @@
plen = 1 + 2 + 2 + os_strlen(nai);
if (hash_len)
plen += 1 + hash_len;
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
plen, EAP_CODE_FINISH, id);
if (msg == NULL)
return;
@@ -753,7 +761,7 @@
if ((flags & 0x80) || !erp) {
sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
return;
}
@@ -781,7 +789,7 @@
sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapSuccess = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -805,7 +813,8 @@
sm->rxInitiate = FALSE;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ pos = eap_hdr_validate(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
sm->eap_if.eapRespData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
@@ -852,7 +861,7 @@
os_memcpy(nai, parse.keyname, parse.keyname_len);
nai[parse.keyname_len] = '\0';
- if (!sm->eap_server) {
+ if (!sm->cfg->eap_server) {
/*
* In passthrough case, EAP-Initiate/Re-auth replaces
* EAP Identity exchange. Use keyName-NAI as the user identity
@@ -1015,7 +1024,7 @@
sm->eap_if.eapReq = TRUE;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1108,8 +1117,8 @@
sm->eap_if.eapTimeout = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR, MAC2STR(sm->peer_addr));
}
@@ -1120,7 +1129,7 @@
eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1149,7 +1158,7 @@
*/
sm->start_reauth = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1160,17 +1169,26 @@
SM_ENTER_GLOBAL(EAP, INITIALIZE);
else if (!sm->eap_if.portEnabled)
SM_ENTER_GLOBAL(EAP, DISABLED);
- else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
- if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+ else if (sm->num_rounds > sm->cfg->max_auth_rounds) {
+ if (sm->num_rounds == sm->cfg->max_auth_rounds + 1) {
wpa_printf(MSG_DEBUG, "EAP: more than %d "
"authentication rounds - abort",
- EAP_MAX_AUTH_ROUNDS);
+ sm->cfg->max_auth_rounds);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > sm->cfg->max_auth_rounds_short) {
+ if (sm->num_rounds_short ==
+ sm->cfg->max_auth_rounds_short + 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: more than %d authentication rounds (short) - abort",
+ sm->cfg->max_auth_rounds_short);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else switch (sm->EAP_state) {
case EAP_INITIALIZE:
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
if (!sm->rxResp)
SM_ENTER(EAP, SELECT_ACTION);
else if (sm->rxResp &&
@@ -1333,7 +1351,7 @@
else if (sm->decision == DECISION_INITIATE_REAUTH_START)
SM_ENTER(EAP, INITIATE_REAUTH_START);
#ifdef CONFIG_ERP
- else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ else if (sm->cfg->eap_server && sm->cfg->erp && sm->rxInitiate)
SM_ENTER(EAP, INITIATE_RECEIVED);
#endif /* CONFIG_ERP */
else
@@ -1343,7 +1361,7 @@
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_INITIATE_RECEIVED:
- if (!sm->eap_server)
+ if (!sm->cfg->eap_server)
SM_ENTER(EAP, SELECT_ACTION);
break;
case EAP_TIMEOUT_FAILURE:
@@ -1669,9 +1687,9 @@
}
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
{
- EapType next;
+ enum eap_type next;
int idx = sm->user_eap_method_index;
/* In theory, there should be no problems with starting
@@ -1703,7 +1721,7 @@
static int eap_sm_Policy_getDecision(struct eap_sm *sm)
{
- if (!sm->eap_server && sm->identity && !sm->start_reauth) {
+ if (!sm->cfg->eap_server && sm->identity && !sm->start_reauth) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
return DECISION_PASSTHROUGH;
}
@@ -1783,7 +1801,7 @@
}
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method)
{
return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
}
@@ -1834,7 +1852,8 @@
*/
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *conf)
+ const struct eap_config *conf,
+ const struct eap_session_data *sess)
{
struct eap_sm *sm;
@@ -1844,53 +1863,15 @@
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
- sm->ssl_ctx = conf->ssl_ctx;
- sm->msg_ctx = conf->msg_ctx;
- sm->eap_sim_db_priv = conf->eap_sim_db_priv;
- sm->backend_auth = conf->backend_auth;
- sm->eap_server = conf->eap_server;
- if (conf->pac_opaque_encr_key) {
- sm->pac_opaque_encr_key = os_malloc(16);
- if (sm->pac_opaque_encr_key) {
- os_memcpy(sm->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (sm->eap_fast_a_id) {
- os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- sm->eap_fast_prov = conf->eap_fast_prov;
- sm->pac_key_lifetime = conf->pac_key_lifetime;
- sm->pac_key_refresh_time = conf->pac_key_refresh_time;
- sm->eap_teap_auth = conf->eap_teap_auth;
- sm->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
- sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- sm->tnc = conf->tnc;
- sm->wps = conf->wps;
- if (conf->assoc_wps_ie)
- sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
- if (conf->assoc_p2p_ie)
- sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
- if (conf->peer_addr)
- os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
- sm->fragment_size = conf->fragment_size;
- sm->pwd_group = conf->pwd_group;
- sm->pbc_in_m1 = conf->pbc_in_m1;
- sm->server_id = conf->server_id;
- sm->server_id_len = conf->server_id_len;
- sm->erp = conf->erp;
- sm->tls_session_lifetime = conf->tls_session_lifetime;
- sm->tls_flags = conf->tls_flags;
-
+ sm->cfg = conf;
+ if (sess->assoc_wps_ie)
+ sm->assoc_wps_ie = wpabuf_dup(sess->assoc_wps_ie);
+ if (sess->assoc_p2p_ie)
+ sm->assoc_p2p_ie = wpabuf_dup(sess->assoc_p2p_ie);
+ if (sess->peer_addr)
+ os_memcpy(sm->peer_addr, sess->peer_addr, ETH_ALEN);
#ifdef CONFIG_TESTING_OPTIONS
- sm->tls_test_flags = conf->tls_test_flags;
+ sm->tls_test_flags = sess->tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
@@ -1920,9 +1901,6 @@
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
os_free(sm->serial_num);
- os_free(sm->pac_opaque_encr_key);
- os_free(sm->eap_fast_a_id);
- os_free(sm->eap_fast_a_id_info);
wpabuf_free(sm->eap_if.aaaEapReqData);
wpabuf_free(sm->eap_if.aaaEapRespData);
bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
@@ -2112,3 +2090,15 @@
source, user, hex_challenge, hex_response);
}
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void eap_server_config_free(struct eap_config *cfg)
+{
+ if (!cfg)
+ return;
+ os_free(cfg->pac_opaque_encr_key);
+ os_free(cfg->eap_fast_a_id);
+ os_free(cfg->eap_fast_a_id_info);
+ os_free(cfg->server_id);
+ os_free(cfg);
+}
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 5f6a1b3..22dd965 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -100,7 +100,7 @@
return 0;
wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
- data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+ data->reauth = eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv,
username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
@@ -157,7 +157,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
if (permanent == NULL) {
os_free(username);
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -182,7 +182,7 @@
{
struct eap_aka_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -208,7 +208,7 @@
/* TODO: make ANID configurable; see 3GPP TS 24.302 */
char *network_name = "WLAN";
- if (sm->eap_sim_db_priv == NULL) {
+ if (sm->cfg->eap_sim_db_priv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -393,10 +393,13 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (nonce_s == NULL) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
+ /* Use of pseudonyms disabled in configuration */
+ data->next_pseudonym = NULL;
+ } else if (!nonce_s) {
data->next_pseudonym =
eap_sim_db_get_next_pseudonym(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -404,10 +407,13 @@
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
+ /* Use of fast reauth disabled in configuration */
+ data->next_reauth_id = NULL;
+ } else if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
data->next_reauth_id =
eap_sim_db_get_next_reauth_id(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -499,7 +505,7 @@
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -576,7 +582,7 @@
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -589,7 +595,7 @@
* Session-Id calculation after receiving response from the peer and
* after all other checks pass. */
os_memcpy(data->reauth_mac,
- (wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN),
+ wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
EAP_SIM_MAC_LEN);
return buf;
@@ -761,7 +767,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -797,7 +803,7 @@
size_t identity_len;
int res;
- res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+ res = eap_sim_db_get_aka_auth(sm->cfg->eap_sim_db_priv, data->permanent,
data->rand, data->autn, data->ik,
data->ck, data->res, &data->res_len, sm);
if (res == EAP_SIM_DB_PENDING) {
@@ -992,7 +998,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1000,14 +1006,15 @@
eap_aka_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1015,7 +1022,7 @@
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1045,7 +1052,7 @@
* maintaining a local flag stating whether this AUTS has already been
* reported. */
if (!data->auts_reported &&
- eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_resynchronize(sm->cfg->eap_sim_db_priv, data->permanent,
attr->auts, data->rand)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
@@ -1112,7 +1119,7 @@
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1122,7 +1129,7 @@
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1130,7 +1137,7 @@
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1138,7 +1145,8 @@
}
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -1147,7 +1155,7 @@
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_aka_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index 71580bf..71fab96 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -84,11 +84,11 @@
eap_eke_state(data, IDENTITY);
data->serverid_type = EAP_EKE_ID_OPAQUE;
- for (i = 0; i < sm->server_id_len; i++) {
- if (sm->server_id[i] == '.' &&
+ for (i = 0; i < sm->cfg->server_id_len; i++) {
+ if (sm->cfg->server_id[i] == '.' &&
data->serverid_type == EAP_EKE_ID_OPAQUE)
data->serverid_type = EAP_EKE_ID_FQDN;
- if (sm->server_id[i] == '@')
+ if (sm->cfg->server_id[i] == '@')
data->serverid_type = EAP_EKE_ID_NAI;
}
@@ -186,7 +186,7 @@
wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
- plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+ plen = 2 + 4 * 4 + 1 + sm->cfg->server_id_len;
msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
if (msg == NULL)
return NULL;
@@ -223,7 +223,7 @@
/* Server IDType + Identity */
wpabuf_put_u8(msg, data->serverid_type);
- wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(msg, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_free(data->msgs);
data->msgs = wpabuf_dup(msg);
@@ -252,7 +252,7 @@
if (eap_eke_derive_key(&data->sess, sm->user->password,
sm->user->password_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, data->key) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -338,7 +338,7 @@
wpabuf_put(msg, prot_len);
if (eap_eke_derive_ka(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_p, data->nonce_s) < 0) {
wpabuf_free(msg);
@@ -552,7 +552,7 @@
}
if (eap_eke_derive_ke_ki(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -641,7 +641,8 @@
return;
}
- if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+ if (eap_eke_derive_msk(&data->sess, sm->cfg->server_id,
+ sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_s, data->nonce_p,
data->msk, data->emsk) < 0) {
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index a63f820..0270821 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -108,8 +108,8 @@
}
-static EapType eap_fast_req_failure(struct eap_sm *sm,
- struct eap_fast_data *data)
+static enum eap_type eap_fast_req_failure(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
/* TODO: send Result TLV(FAILURE) */
eap_fast_state(data, FAILURE);
@@ -278,7 +278,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ sks = eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +304,7 @@
{
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
- eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -440,7 +440,7 @@
return NULL;
}
- if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_cipher_list(sm->cfg->ssl_ctx, data->ssl.conn,
ciphers) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
"suites");
@@ -448,7 +448,8 @@
return NULL;
}
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_fast_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
@@ -457,47 +458,48 @@
return NULL;
}
- if (sm->pac_opaque_encr_key == NULL) {
+ if (sm->cfg->pac_opaque_encr_key == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
"configured");
eap_fast_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (sm->eap_fast_a_id == NULL) {
+ if (sm->cfg->eap_fast_a_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id = os_memdup(sm->eap_fast_a_id, sm->eap_fast_a_id_len);
+ data->srv_id = os_memdup(sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
if (data->srv_id == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_len = sm->eap_fast_a_id_len;
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (sm->eap_fast_a_id_info == NULL) {
+ if (sm->cfg->eap_fast_a_id_info == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (data->srv_id_info == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -552,8 +554,8 @@
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
"information");
eap_fast_state(data, FAILURE);
@@ -872,7 +874,8 @@
case START:
return eap_fast_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_fast_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -943,15 +946,14 @@
static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -973,7 +975,8 @@
struct eap_fast_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -999,8 +1002,9 @@
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
"TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -1008,14 +1012,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1035,8 +1042,9 @@
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1047,6 +1055,7 @@
"Identity not found in the user "
"database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
break;
}
@@ -1057,23 +1066,28 @@
* Only EAP-MSCHAPv2 is allowed for anonymous
* provisioning.
*/
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_MSCHAPV2;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_fast_update_icmk(sm, data);
eap_fast_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1087,7 +1101,7 @@
break;
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1335,8 +1349,8 @@
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
"use unauthenticated provisioning which is "
"disabled");
@@ -1344,8 +1358,8 @@
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
eap_fast_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1397,7 +1411,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
@@ -1457,7 +1471,7 @@
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1474,7 +1488,8 @@
static int eap_fast_process_phase2_start(struct eap_sm *sm,
struct eap_fast_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
os_free(sm->identity);
@@ -1488,10 +1503,12 @@
"Phase2 Identity not found "
"in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
"known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
@@ -1499,10 +1516,11 @@
eap_fast_state(data, PHASE2_METHOD);
} else {
eap_fast_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_fast_phase2_init(sm, data, next_type);
+ return eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index bebb17f..a774275 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -117,7 +117,7 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
data->rand_server, EAP_GPSK_RAND_LEN);
- len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
+ len = 1 + 2 + sm->cfg->server_id_len + EAP_GPSK_RAND_LEN + 2 +
data->csuite_count * sizeof(struct eap_gpsk_csuite);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -129,8 +129,8 @@
}
wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
wpabuf_put_be16(req,
data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -152,7 +152,7 @@
wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
- len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
+ len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->cfg->server_id_len +
sizeof(struct eap_gpsk_csuite) + 2 + miclen;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -168,8 +168,8 @@
wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
csuite = wpabuf_put(req, sizeof(*csuite));
WPA_PUT_BE32(csuite->vendor, data->vendor);
WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -294,8 +294,8 @@
eap_gpsk_state(data, FAILURE);
return;
}
- if (alen != sm->server_id_len ||
- os_memcmp(pos, sm->server_id, alen) != 0) {
+ if (alen != sm->cfg->server_id_len ||
+ os_memcmp(pos, sm->cfg->server_id, alen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
"GPSK-2 did not match");
eap_gpsk_state(data, FAILURE);
@@ -409,7 +409,7 @@
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->msk, data->emsk,
data->sk, &data->sk_len,
data->pk, &data->pk_len) < 0) {
@@ -423,7 +423,8 @@
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id,
+ sm->cfg->server_id_len,
EAP_TYPE_GPSK,
data->session_id, &data->id_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 32e6872..897637e 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -87,8 +87,8 @@
if (data == NULL)
return NULL;
data->state = MSG;
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- IKEV2_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : IKEV2_FRAGMENT_SIZE;
data->ikev2.state = SA_INIT;
data->ikev2.peer_auth = PEER_AUTH_SECRET;
data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
@@ -103,10 +103,10 @@
data->ikev2.proposal.encr = ENCR_AES_CBC;
data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
- data->ikev2.IDi = os_memdup(sm->server_id, sm->server_id_len);
+ data->ikev2.IDi = os_memdup(sm->cfg->server_id, sm->cfg->server_id_len);
if (data->ikev2.IDi == NULL)
goto failed;
- data->ikev2.IDi_len = sm->server_id_len;
+ data->ikev2.IDi_len = sm->cfg->server_id_len;
data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
data->ikev2.cb_ctx = sm;
@@ -414,7 +414,7 @@
eap_ikev2_state(data, FAIL);
return;
}
-
+
if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
if (eap_ikev2_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 79ed344..f37c9c3 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -22,7 +22,8 @@
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_server_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -42,7 +43,7 @@
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_server_get_type(const char *name, int *vendor)
+enum eap_type eap_server_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -69,7 +70,8 @@
* is not needed anymore.
*/
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
@@ -163,7 +165,7 @@
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_server_get_name(int vendor, EapType type)
+const char * eap_server_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index e9e03b0..8a1621a 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -109,7 +109,7 @@
return NULL;
}
- ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->cfg->server_id_len;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
@@ -131,7 +131,7 @@
wpabuf_put(req, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
data->auth_challenge, CHALLENGE_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 5e125ac..02d8b8e 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -105,8 +105,8 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime ||
- tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!sm->cfg->tls_session_lifetime ||
+ tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -336,7 +336,7 @@
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
- if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
/* Fast-connect: IPMK|CMK = TK */
os_memcpy(data->ipmk, tk, 40);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -521,7 +521,8 @@
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
@@ -585,7 +586,7 @@
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
- int vendor, EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
@@ -1020,7 +1021,7 @@
}
#ifdef EAP_SERVER_TNC
- if (data->state != PHASE2_SOH && sm->tnc &&
+ if (data->state != PHASE2_SOH && sm->cfg->tnc &&
data->peap_version == 0) {
eap_peap_state(data, PHASE2_SOH);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
@@ -1077,7 +1078,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
@@ -1237,8 +1238,8 @@
}
if (data->state == SUCCESS ||
- !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ !tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 0eab893..511973c 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -68,7 +68,7 @@
data->rand_s, EAP_PSK_RAND_LEN);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
- sizeof(*psk) + sm->server_id_len,
+ sizeof(*psk) + sm->cfg->server_id_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -80,7 +80,7 @@
psk = wpabuf_put(req, sizeof(*psk));
psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
@@ -110,13 +110,13 @@
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
- buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
+ buflen = sm->cfg->server_id_len + EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL)
goto fail;
- os_memcpy(buf, sm->server_id, sm->server_id_len);
- os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(buf, sm->cfg->server_id, sm->cfg->server_id_len);
+ os_memcpy(buf + sm->cfg->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
os_free(buf);
goto fail;
@@ -293,7 +293,7 @@
os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
- buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
+ buflen = data->id_p_len + sm->cfg->server_id_len + 2 * EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL) {
data->state = FAILURE;
@@ -301,8 +301,8 @@
}
os_memcpy(buf, data->id_p, data->id_p_len);
pos = buf + data->id_p_len;
- os_memcpy(pos, sm->server_id, sm->server_id_len);
- pos += sm->server_id_len;
+ os_memcpy(pos, sm->cfg->server_id, sm->cfg->server_id_len);
+ pos += sm->cfg->server_id_len;
os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index a8087c1..6bf3a23 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -97,7 +97,7 @@
if (data == NULL)
return NULL;
- data->group_num = sm->pwd_group;
+ data->group_num = sm->cfg->pwd_group;
wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
data->group_num);
data->state = PWD_ID_Req;
@@ -134,7 +134,7 @@
data->in_frag_pos = data->out_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
/* use default MTU from RFC 5931 if not configured otherwise */
- data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
+ data->mtu = sm->cfg->fragment_size > 0 ? sm->cfg->fragment_size : 1020;
return data;
}
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 2fc2c05..56cfbfb 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -123,7 +123,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
plen = 4;
- plen += 2 + sm->server_id_len;
+ plen += 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
if (msg == NULL) {
data->state = FAILURE;
@@ -135,7 +135,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -158,7 +158,7 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
data->rand_s, EAP_SAKE_RAND_LEN);
- plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
+ plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
if (msg == NULL) {
data->state = FAILURE;
@@ -171,7 +171,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -198,7 +198,7 @@
wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 0,
wpabuf_head(msg), wpabuf_len(msg), mic, mic))
{
@@ -351,7 +351,7 @@
}
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p) < 0) {
@@ -392,7 +392,7 @@
}
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p) < 0) {
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 8562c64..d7ac87c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -76,7 +76,7 @@
{
struct eap_sim_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
return NULL;
}
@@ -150,18 +150,24 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (nonce_s == NULL) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
+ /* Use of pseudonyms disabled in configuration */
+ data->next_pseudonym = NULL;
+ } else if (!nonce_s) {
data->next_pseudonym =
- eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_pseudonym(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
/* Do not update pseudonym during re-authentication */
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
+ /* Use of fast reauth disabled in configuration */
+ data->next_reauth_id = NULL;
+ } else if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
data->next_reauth_id =
- eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_reauth_id(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
@@ -234,7 +240,7 @@
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -273,7 +279,7 @@
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -286,7 +292,7 @@
* Session-Id calculation after receiving response from the peer and
* after all other checks pass. */
os_memcpy(data->reauth_mac,
- (wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN),
+ wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
EAP_SIM_MAC_LEN);
return buf;
@@ -469,7 +475,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
username);
data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
@@ -491,7 +497,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
@@ -532,7 +538,7 @@
data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
+ sm->cfg->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
if (data->num_chal == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
@@ -593,7 +599,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -601,12 +607,13 @@
eap_sim_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id, data->counter + 1,
data->mk);
data->next_reauth_id = NULL;
@@ -666,7 +673,7 @@
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -674,12 +681,13 @@
eap_sim_state(data, SUCCESS);
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id,
data->counter + 1, data->mk);
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -688,7 +696,7 @@
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_sim_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
diff --git a/src/eap_server/eap_server_teap.c b/src/eap_server/eap_server_teap.c
index d8e5414..a2cbf7a 100644
--- a/src/eap_server/eap_server_teap.c
+++ b/src/eap_server/eap_server_teap.c
@@ -31,7 +31,7 @@
enum {
START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID,
PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC,
- FAILURE_SEND_RESULT, SUCCESS, FAILURE
+ FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE
} state;
u8 teap_version;
@@ -56,7 +56,10 @@
size_t srv_id_len;
char *srv_id_info;
+ unsigned int basic_auth_not_done:1;
+ unsigned int inner_eap_not_done:1;
int anon_provisioning;
+ int skipped_inner_auth;
int send_new_pac; /* server triggered re-keying of Tunnel PAC */
struct wpabuf *pending_phase2_resp;
struct wpabuf *server_outer_tlvs;
@@ -70,6 +73,7 @@
int pac_key_refresh_time;
enum teap_error_codes error_code;
+ enum teap_identity_types cur_id_type;
};
@@ -100,6 +104,8 @@
return "REQUEST_PAC";
case FAILURE_SEND_RESULT:
return "FAILURE_SEND_RESULT";
+ case SUCCESS_SEND_RESULT:
+ return "SUCCESS_SEND_RESULT";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -119,8 +125,8 @@
}
-static EapType eap_teap_req_failure(struct eap_teap_data *data,
- enum teap_error_codes error)
+static enum eap_type eap_teap_req_failure(struct eap_teap_data *data,
+ enum teap_error_codes error)
{
eap_teap_state(data, FAILURE_SEND_RESULT);
return EAP_TYPE_NONE;
@@ -285,7 +291,7 @@
int res;
/* RFC 7170, Section 5.1 */
- res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn,
+ res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn,
TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
data->simck_msk, EAP_TEAP_SIMCK_LEN);
if (res)
@@ -308,8 +314,9 @@
wpa_printf(MSG_DEBUG, "EAP-TEAP: Deriving ICMK[%d] (S-IMCK and CMK)",
data->simck_idx + 1);
- if (sm->eap_teap_auth == 1)
- return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ if (sm->cfg->eap_teap_auth == 1)
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
data->cmk_msk);
if (!data->phase2_method || !data->phase2_priv) {
@@ -332,7 +339,8 @@
&emsk_len);
}
- res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
msk, msk_len, emsk, emsk_len,
data->simck_msk, data->cmk_msk,
data->simck_emsk, data->cmk_emsk);
@@ -366,7 +374,8 @@
/* TODO: Add anon-DH TLS cipher suites (and if one is negotiated,
* enforce inner EAP with mutual authentication to be used) */
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_teap_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO,
@@ -375,48 +384,49 @@
return NULL;
}
- if (!sm->pac_opaque_encr_key) {
+ if (!sm->cfg->pac_opaque_encr_key) {
wpa_printf(MSG_INFO,
"EAP-TEAP: No PAC-Opaque encryption key configured");
eap_teap_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (!sm->eap_fast_a_id) {
+ if (!sm->cfg->eap_fast_a_id) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured");
eap_teap_reset(sm, data);
return NULL;
}
- data->srv_id = os_malloc(sm->eap_fast_a_id_len);
+ data->srv_id = os_malloc(sm->cfg->eap_fast_a_id_len);
if (!data->srv_id) {
eap_teap_reset(sm, data);
return NULL;
}
- os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
- data->srv_id_len = sm->eap_fast_a_id_len;
+ os_memcpy(data->srv_id, sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (!sm->eap_fast_a_id_info) {
+ if (!sm->cfg->eap_fast_a_id_info) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID-Info configured");
eap_teap_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (!data->srv_id_info) {
eap_teap_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -496,8 +506,8 @@
wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Failed to get cipher information");
eap_teap_state(data, FAILURE);
@@ -523,30 +533,65 @@
struct eap_teap_data *data,
u8 id)
{
- struct wpabuf *req;
+ struct wpabuf *req, *id_tlv = NULL;
- if (sm->eap_teap_auth == 1) {
+ if (sm->cfg->eap_teap_auth == 1 ||
+ (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->vendor == EAP_VENDOR_IETF &&
+ data->phase2_method->method == EAP_TYPE_IDENTITY)) {
+ switch (sm->cfg->eap_teap_id) {
+ case EAP_TEAP_ID_ALLOW_ANY:
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER:
+ case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_MACHINE:
+ case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE:
+ if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER)
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ else
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ }
+ }
+
+ if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth");
+ data->basic_auth_not_done = 1;
req = wpabuf_alloc(sizeof(struct teap_tlv_hdr));
- if (!req)
+ if (!req) {
+ wpabuf_free(id_tlv);
return NULL;
+ }
eap_teap_put_tlv_hdr(req, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ, 0);
- return req;
+ return wpabuf_concat(req, id_tlv);
}
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method");
+ data->inner_eap_not_done = 1;
if (!data->phase2_priv) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Phase 2 method not initialized");
+ wpabuf_free(id_tlv);
return NULL;
}
req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
- if (!req)
+ if (!req) {
+ wpabuf_free(id_tlv);
return NULL;
+ }
wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-TEAP: Phase 2 EAP-Request", req);
- return eap_teap_tlv_eap_payload(req);
+
+ return wpabuf_concat(eap_teap_tlv_eap_payload(req), id_tlv);
}
@@ -563,12 +608,14 @@
return NULL;
if (data->send_new_pac || data->anon_provisioning ||
- data->phase2_method)
+ data->basic_auth_not_done || data->inner_eap_not_done ||
+ data->phase2_method || sm->cfg->eap_teap_separate_result)
data->final_result = 0;
else
data->final_result = 1;
- if (!data->final_result || data->eap_seq > 0) {
+ if (!data->final_result || data->eap_seq > 0 ||
+ sm->cfg->eap_teap_auth == 1) {
/* Intermediate-Result */
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)");
@@ -842,7 +889,8 @@
case START:
return eap_teap_build_start(sm, data, id);
case PHASE1B:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_teap_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -899,6 +947,10 @@
req = wpabuf_concat(
req, eap_teap_tlv_error(data->error_code));
break;
+ case SUCCESS_SEND_RESULT:
+ req = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
+ data->final_result = 1;
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
__func__, data->state);
@@ -930,15 +982,14 @@
static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -950,11 +1001,33 @@
}
+static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data,
+ enum teap_identity_types id_type)
+{
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_USER)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE &&
+ id_type != data->cur_id_type)
+ return 0;
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY &&
+ id_type != TEAP_IDENTITY_TYPE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ return 1;
+}
+
+
static void eap_teap_process_phase2_response(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -982,8 +1055,9 @@
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Peer Nak'ed required TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, 0);
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -991,14 +1065,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, 0);
}
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1018,17 +1095,26 @@
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
switch (data->state) {
case PHASE2_ID:
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ break;
+ }
if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-TEAP: Phase 2 Identity not found in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(
data, TEAP_ERROR_INNER_METHOD);
break;
@@ -1039,23 +1125,33 @@
/* TODO: Allow any inner EAP method that provides
* mutual authentication and EMSK derivation (i.e.,
* EAP-pwd or EAP-EKE). */
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_PWD;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_teap_update_icmk(sm, data);
+ if (data->state == PHASE2_METHOD &&
+ (sm->cfg->eap_teap_id !=
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE))
+ data->inner_eap_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1069,13 +1165,14 @@
break;
}
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
}
static void eap_teap_process_phase2_eap(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
struct eap_hdr *hdr;
size_t len;
@@ -1102,7 +1199,8 @@
(unsigned long) len);
switch (hdr->code) {
case EAP_CODE_RESPONSE:
- eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len);
+ eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len,
+ id_type);
break;
default:
wpa_printf(MSG_INFO,
@@ -1115,11 +1213,20 @@
static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
u8 *pos, *end, *username, *password, *new_id;
u8 userlen, passlen;
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
pos = in_data;
end = pos + in_len;
@@ -1197,6 +1304,9 @@
sm->identity = new_id;
sm->identity_len = userlen;
}
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)
+ data->basic_auth_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING);
eap_teap_update_icmk(sm, data);
}
@@ -1444,7 +1554,8 @@
return;
}
- if (!data->final_result &&
+ if (sm->cfg->eap_teap_auth != 1 &&
+ !data->skipped_inner_auth &&
tlv.iresult != TEAP_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Crypto-Binding TLV without intermediate Success Result");
@@ -1466,16 +1577,16 @@
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled");
eap_teap_state(data, FAILURE);
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
eap_teap_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1496,30 +1607,55 @@
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Server triggered re-keying of Tunnel PAC");
eap_teap_state(data, REQUEST_PAC);
- } else if (data->final_result)
+ } else if (data->final_result) {
eap_teap_state(data, SUCCESS);
+ } else if (sm->cfg->eap_teap_separate_result) {
+ eap_teap_state(data, SUCCESS_SEND_RESULT);
+ }
}
if (tlv.basic_auth_resp) {
- if (sm->eap_teap_auth != 1) {
+ if (sm->cfg->eap_teap_auth != 1) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Unexpected Basic-Password-Auth-Resp when trying to use inner EAP");
eap_teap_state(data, FAILURE);
return;
}
eap_teap_process_basic_auth_resp(sm, data, tlv.basic_auth_resp,
- tlv.basic_auth_resp_len);
+ tlv.basic_auth_resp_len,
+ tlv.identity_type);
}
if (tlv.eap_payload_tlv) {
- if (sm->eap_teap_auth == 1) {
+ if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Unexpected EAP Payload TLV when trying to use Basic-Password-Auth");
eap_teap_state(data, FAILURE);
return;
}
eap_teap_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
- tlv.eap_payload_tlv_len);
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
+ }
+
+ if (data->state == SUCCESS_SEND_RESULT &&
+ tlv.result == TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer agreed with final success - authentication completed");
+ eap_teap_state(data, SUCCESS);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with basic password authentication for second credential");
+ eap_teap_state(data, PHASE2_BASIC_AUTH);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with inner EAP authentication for second credential");
+ eap_teap_state(data, PHASE2_ID);
+ if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0)
+ eap_teap_state(data, FAILURE);
}
}
@@ -1544,7 +1680,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (!in_decrypted) {
wpa_printf(MSG_INFO,
@@ -1605,7 +1741,7 @@
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1622,7 +1758,8 @@
static int eap_teap_process_phase2_start(struct eap_sm *sm,
struct eap_teap_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
/* Used PAC and identity is from PAC-Opaque */
@@ -1635,38 +1772,43 @@
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-TEAP: Phase 2 Identity not found in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
eap_teap_state(data, PHASE2_METHOD);
- } else if (sm->eap_teap_pac_no_inner) {
+ } else if (sm->cfg->eap_teap_pac_no_inner) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Used PAC and identity already known - skip inner auth");
+ data->skipped_inner_auth = 1;
/* FIX: Need to derive CMK here. However, how is that
* supposed to be done? RFC 7170 does not tell that for
* the no-inner-auth case. */
- eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
data->cmk_msk);
eap_teap_state(data, CRYPTO_BINDING);
return 1;
- } else if (sm->eap_teap_auth == 1) {
+ } else if (sm->cfg->eap_teap_auth == 1) {
eap_teap_state(data, PHASE2_BASIC_AUTH);
return 1;
} else {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Identity already known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
eap_teap_state(data, PHASE2_METHOD);
}
- } else if (sm->eap_teap_auth == 1) {
+ } else if (sm->cfg->eap_teap_auth == 1) {
eap_teap_state(data, PHASE2_BASIC_AUTH);
return 0;
} else {
eap_teap_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_teap_phase2_init(sm, data, next_type);
+ return eap_teap_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1690,6 +1832,7 @@
case PHASE2_METHOD:
case CRYPTO_BINDING:
case REQUEST_PAC:
+ case SUCCESS_SEND_RESULT:
eap_teap_process_phase2(sm, data, data->ssl.tls_in);
break;
case FAILURE_SEND_RESULT:
@@ -1853,7 +1996,8 @@
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_msk(data->simck_msk, eapKeyData) < 0) {
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
}
@@ -1877,7 +2021,8 @@
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_emsk(data->simck_msk, eapKeyData) < 0) {
+ if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
}
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 0712d4c..c64cebb 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -58,7 +58,7 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1);
@@ -187,7 +187,8 @@
case START:
return eap_tls_build_start(sm, data, id);
case CONTINUE:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn))
data->established = 1;
break;
default:
@@ -267,7 +268,7 @@
}
if (data->ssl.tls_v13 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn)) {
struct wpabuf *plain, *encr;
wpa_printf(MSG_DEBUG,
@@ -315,8 +316,8 @@
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 907101c..b38f1e0 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -18,7 +18,7 @@
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -47,9 +47,9 @@
int verify_peer, int eap_type)
{
u8 session_ctx[8];
- unsigned int flags = sm->tls_flags;
+ unsigned int flags = sm->cfg->tls_flags;
- if (sm->ssl_ctx == NULL) {
+ if (!sm->cfg->ssl_ctx) {
wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
return -1;
}
@@ -57,7 +57,7 @@
data->eap = sm;
data->phase2 = sm->init_phase2;
- data->conn = tls_connection_init(sm->ssl_ctx);
+ data->conn = tls_connection_init(sm->cfg->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
"connection");
@@ -75,17 +75,18 @@
flags |= TLS_CONN_DISABLE_SESSION_TICKET;
os_memcpy(session_ctx, "hostapd", 7);
session_ctx[7] = (u8) eap_type;
- if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ if (tls_connection_set_verify(sm->cfg->ssl_ctx, data->conn, verify_peer,
flags, session_ctx,
sizeof(session_ctx))) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
}
- data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
+ data->tls_out_limit = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : 1398;
if (data->phase2) {
/* Limit the fragment size in the inner TLS authentication
* since the outer authentication with EAP-PEAP does not yet
@@ -99,7 +100,7 @@
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
eap_server_tls_free_in_buf(data);
wpabuf_free(data->tls_out);
data->tls_out = NULL;
@@ -116,7 +117,7 @@
if (out == NULL)
return NULL;
- if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
+ if (tls_connection_export_key(sm->cfg->ssl_ctx, data->conn, label,
context, context_len, out, len)) {
os_free(out);
return NULL;
@@ -170,7 +171,7 @@
return id;
}
- if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
+ if (tls_connection_get_random(sm->cfg->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.client_random == NULL || keys.server_random == NULL)
@@ -340,29 +341,30 @@
WPA_ASSERT(data->tls_out == NULL);
}
- data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
+ data->tls_out = tls_connection_server_handshake(sm->cfg->ssl_ctx,
data->conn,
data->tls_in, NULL);
if (data->tls_out == NULL) {
wpa_printf(MSG_INFO, "SSL: TLS processing failed");
return -1;
}
- if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ if (tls_connection_get_failed(sm->cfg->ssl_ctx, data->conn)) {
/* TLS processing has failed - return error */
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
return -1;
}
- if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+ if (tls_get_version(sm->cfg->ssl_ctx, data->conn,
+ buf, sizeof(buf)) == 0) {
wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
}
if (!sm->serial_num &&
- tls_connection_established(sm->ssl_ctx, data->conn))
- sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
- data->conn);
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn))
+ sm->serial_num = tls_connection_peer_serial_num(
+ sm->cfg->ssl_ctx, data->conn);
return 0;
}
@@ -451,8 +453,7 @@
{
struct wpabuf *buf;
- buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
- plain);
+ buf = tls_connection_encrypt(sm->cfg->ssl_ctx, data->conn, plain);
if (buf == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
return NULL;
@@ -506,7 +507,7 @@
if (proc_msg)
proc_msg(sm, priv, respData);
- if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+ if (tls_connection_get_write_alerts(sm->cfg->ssl_ctx, data->conn) > 1) {
wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
"TLS processing");
res = -1;
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index b568558..f6cdcb1 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -84,8 +84,8 @@
return NULL;
}
- data->fragment_size = sm->fragment_size > 100 ?
- sm->fragment_size - 98 : 1300;
+ data->fragment_size = sm->cfg->fragment_size > 100 ?
+ sm->cfg->fragment_size - 98 : 1300;
return data;
}
@@ -508,7 +508,7 @@
eap_tnc_set_state(data, FAIL);
return;
}
-
+
if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
if (eap_tnc_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 52bff8a..721835d 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -81,7 +81,7 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -480,7 +480,8 @@
case START:
return eap_ttls_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
"starting Phase2");
eap_ttls_state(data, PHASE2_START);
@@ -827,15 +828,14 @@
static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
struct eap_ttls_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -850,7 +850,8 @@
struct eap_ttls_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -875,14 +876,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
- next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
- "initialize EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
return;
}
@@ -930,12 +934,16 @@
}
eap_ttls_state(data, PHASE2_METHOD);
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
- "EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
}
break;
@@ -962,8 +970,8 @@
if (data->state == PHASE2_START) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
- {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
"initialize EAP-Identity");
return;
@@ -1022,7 +1030,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
@@ -1112,11 +1120,11 @@
static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
{
#ifdef EAP_SERVER_TNC
- if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+ if (!sm->cfg->tnc || data->state != SUCCESS || data->tnc_started)
return;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF, EAP_TYPE_TNC)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
eap_ttls_state(data, FAILURE);
return;
@@ -1202,8 +1210,8 @@
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 4a5cb98..364c089 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -103,10 +103,10 @@
data->registrar = registrar;
os_memset(&cfg, 0, sizeof(cfg));
- cfg.wps = sm->wps;
+ cfg.wps = sm->cfg->wps;
cfg.registrar = registrar;
if (registrar) {
- if (sm->wps == NULL || sm->wps->registrar == NULL) {
+ if (!sm->cfg->wps || !sm->cfg->wps->registrar) {
wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
"initialized");
os_free(data);
@@ -138,14 +138,14 @@
cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
}
#endif /* CONFIG_P2P */
- cfg.pbc_in_m1 = sm->pbc_in_m1;
+ cfg.pbc_in_m1 = sm->cfg->pbc_in_m1;
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
return NULL;
}
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- WSC_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : WSC_FRAGMENT_SIZE;
return data;
}
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 74b1c72..b0b7361 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -73,7 +73,7 @@
#define EAP_WFA_UNAUTH_TLS_TYPE 254
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type);
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index b7423d1..5a2ba26 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -775,7 +775,7 @@
const char *identity, const char *radius_cui)
{
struct eapol_state_machine *sm;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
if (eapol == NULL)
return NULL;
@@ -823,35 +823,12 @@
else
sm->portValid = TRUE;
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.eap_server = eapol->conf.eap_server;
- eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
- eap_conf.msg_ctx = eapol->conf.msg_ctx;
- eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
- eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
- eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
- eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
- eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
- eap_conf.eap_teap_auth = eapol->conf.eap_teap_auth;
- eap_conf.eap_teap_pac_no_inner = eapol->conf.eap_teap_pac_no_inner;
- eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
- eap_conf.tnc = eapol->conf.tnc;
- eap_conf.wps = eapol->conf.wps;
- eap_conf.assoc_wps_ie = assoc_wps_ie;
- eap_conf.assoc_p2p_ie = assoc_p2p_ie;
- eap_conf.peer_addr = addr;
- eap_conf.fragment_size = eapol->conf.fragment_size;
- eap_conf.pwd_group = eapol->conf.pwd_group;
- eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
- eap_conf.server_id = eapol->conf.server_id;
- eap_conf.server_id_len = eapol->conf.server_id_len;
- eap_conf.erp = eapol->conf.erp;
- eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
- eap_conf.tls_flags = eapol->conf.tls_flags;
- sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ eap_sess.assoc_wps_ie = assoc_wps_ie;
+ eap_sess.assoc_p2p_ie = assoc_p2p_ie;
+ eap_sess.peer_addr = addr;
+ sm->eap = eap_server_sm_init(sm, &eapol_cb, eapol->conf.eap_cfg,
+ &eap_sess);
if (sm->eap == NULL) {
eapol_auth_free(sm);
return NULL;
@@ -1186,19 +1163,12 @@
static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
struct eapol_auth_config *src)
{
+ dst->eap_cfg = src->eap_cfg;
dst->ctx = src->ctx;
dst->eap_reauth_period = src->eap_reauth_period;
dst->wpa = src->wpa;
dst->individual_wep_key_len = src->individual_wep_key_len;
- dst->eap_server = src->eap_server;
- dst->ssl_ctx = src->ssl_ctx;
- dst->msg_ctx = src->msg_ctx;
- dst->eap_sim_db_priv = src->eap_sim_db_priv;
os_free(dst->eap_req_id_text);
- dst->pwd_group = src->pwd_group;
- dst->pbc_in_m1 = src->pbc_in_m1;
- dst->server_id = src->server_id;
- dst->server_id_len = src->server_id_len;
if (src->eap_req_id_text) {
dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
src->eap_req_id_text_len);
@@ -1209,36 +1179,6 @@
dst->eap_req_id_text = NULL;
dst->eap_req_id_text_len = 0;
}
- if (src->pac_opaque_encr_key) {
- dst->pac_opaque_encr_key = os_memdup(src->pac_opaque_encr_key,
- 16);
- if (dst->pac_opaque_encr_key == NULL)
- goto fail;
- } else
- dst->pac_opaque_encr_key = NULL;
- if (src->eap_fast_a_id) {
- dst->eap_fast_a_id = os_memdup(src->eap_fast_a_id,
- src->eap_fast_a_id_len);
- if (dst->eap_fast_a_id == NULL)
- goto fail;
- dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
- } else
- dst->eap_fast_a_id = NULL;
- if (src->eap_fast_a_id_info) {
- dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL)
- goto fail;
- } else
- dst->eap_fast_a_id_info = NULL;
- dst->eap_fast_prov = src->eap_fast_prov;
- dst->pac_key_lifetime = src->pac_key_lifetime;
- dst->pac_key_refresh_time = src->pac_key_refresh_time;
- dst->eap_teap_auth = src->eap_teap_auth;
- dst->eap_teap_pac_no_inner = src->eap_teap_pac_no_inner;
- dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
- dst->tnc = src->tnc;
- dst->wps = src->wps;
- dst->fragment_size = src->fragment_size;
os_free(dst->erp_domain);
if (src->erp_domain) {
@@ -1249,9 +1189,6 @@
dst->erp_domain = NULL;
}
dst->erp_send_reauth_start = src->erp_send_reauth_start;
- dst->erp = src->erp;
- dst->tls_session_lifetime = src->tls_session_lifetime;
- dst->tls_flags = src->tls_flags;
return 0;
@@ -1265,12 +1202,6 @@
{
os_free(conf->eap_req_id_text);
conf->eap_req_id_text = NULL;
- os_free(conf->pac_opaque_encr_key);
- conf->pac_opaque_encr_key = NULL;
- os_free(conf->eap_fast_a_id);
- conf->eap_fast_a_id = NULL;
- os_free(conf->eap_fast_a_id_info);
- conf->eap_fast_a_id_info = NULL;
os_free(conf->erp_domain);
conf->erp_domain = NULL;
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 41b6b1b..5fe89c6 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -15,37 +15,14 @@
#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3)
struct eapol_auth_config {
+ const struct eap_config *eap_cfg;
int eap_reauth_period;
int wpa;
int individual_wep_key_len;
- int eap_server;
- void *ssl_ctx;
- void *msg_ctx;
- void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
int erp_send_reauth_start;
char *erp_domain; /* a copy of this will be allocated */
- int erp; /* Whether ERP is enabled on authentication server */
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- int eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
- int eap_sim_aka_result_ind;
- int tnc;
- struct wps_context *wps;
- int fragment_size;
- u16 pwd_group;
- int pbc_in_m1;
- const u8 *server_id;
- size_t server_id_len;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
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 @@
}
+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 @@
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/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 1c4dc3e..69e5758 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -141,6 +141,24 @@
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
if (sm->oki)
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ /* The standard doesn't say it but we should clear out the latest
+ * and old key values. Why would we keep advertising them if
+ * they've been deleted and the key server has been changed?
+ */
+ os_free(sm->oki);
+ sm->oki = NULL;
+ sm->otx = FALSE;
+ sm->orx = FALSE;
+ sm->oan = 0;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+ os_free(sm->lki);
+ sm->lki = NULL;
+ sm->lrx = FALSE;
+ sm->ltx = FALSE;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
@@ -212,18 +230,6 @@
SM_STATE(CP, RECEIVE)
{
SM_ENTRY(CP, RECEIVE);
- /* RECEIVE state machine not keep with Figure 12-2 in
- * IEEE Std 802.1X-2010 */
- if (sm->oki) {
- ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
- os_free(sm->oki);
- }
- sm->oki = sm->lki;
- sm->oan = sm->lan;
- sm->otx = sm->ltx;
- sm->orx = sm->lrx;
- ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
- sm->otx, sm->orx);
sm->lki = os_malloc(sizeof(*sm->lki));
if (!sm->lki) {
@@ -313,24 +319,29 @@
sm->lki = NULL;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
- sm->new_sak = FALSE;
}
SM_STATE(CP, RETIRE)
{
SM_ENTRY(CP, RETIRE);
- /* RETIRE state machine not keep with Figure 12-2 in
- * IEEE Std 802.1X-2010 */
if (sm->oki) {
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
os_free(sm->oki);
sm->oki = NULL;
}
- sm->orx = FALSE;
- sm->otx = FALSE;
+ sm->oki = sm->lki;
+ sm->otx = sm->ltx;
+ sm->orx = sm->lrx;
+ sm->oan = sm->lan;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
sm->otx, sm->orx);
+ sm->lki = NULL;
+ sm->ltx = FALSE;
+ sm->lrx = FALSE;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index b4455c8..3dbd3ca 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1085,7 +1085,17 @@
wpa_printf(MSG_DEBUG,
"KaY: My MI - received MN %u, most recently transmitted MN %u",
mn, participant->mn);
- if (mn == participant->mn)
+ /* IEEE Std 802.1X-2010 is not exactly clear
+ * which values of MN should be accepted here.
+ * It uses "acceptably recent MN" language
+ * without defining what would be acceptable
+ * recent. For now, allow the last two used MN
+ * values (i.e., peer having copied my MI,MN
+ * from either of the last two MKPDUs that I
+ * have sent). */
+ if (mn == participant->mn ||
+ (participant->mn > 1 &&
+ mn == participant->mn - 1))
return TRUE;
}
}
@@ -1277,7 +1287,7 @@
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay *kay = participant->kay;
unsigned int length;
- u32 pn = 1;
+ u32 olpn, llpn;
length = ieee802_1x_mka_get_sak_use_length(participant);
body = wpabuf_put(buf, length);
@@ -1297,18 +1307,31 @@
/* data delay protect */
body->delay_protect = kay->mka_hello_time <= MKA_BOUNDED_HELLO_TIME;
- /* lowest accept packet number */
- pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
- if (pn > kay->pn_exhaustion) {
- wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
- if (participant->is_key_server)
- participant->new_sak = TRUE;
+ /* lowest accept packet numbers */
+ olpn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
+ body->olpn = host_to_be32(olpn);
+ llpn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
+ body->llpn = host_to_be32(llpn);
+ if (participant->is_key_server) {
+ /* The CP will spend most of it's time in RETIRE where only
+ * the old key is populated. Therefore we should be checking
+ * the OLPN most of the time.
+ */
+ if (participant->lrx) {
+ if (llpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My LLPN exhaustion");
+ participant->new_sak = TRUE;
+ }
+ } else {
+ if (olpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My OLPN exhaustion");
+ participant->new_sak = TRUE;
+ }
+ }
}
- body->llpn = host_to_be32(pn);
- pn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
- body->olpn = host_to_be32(pn);
-
/* plain tx, plain rx */
body->ptx = !kay->macsec_protect;
body->prx = kay->macsec_validate != Strict;
@@ -1358,15 +1381,12 @@
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct receive_sc *rxsc;
- struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
u32 lpn;
- Boolean all_receiving;
- Boolean found;
struct ieee802_1x_kay *kay = participant->kay;
+ u32 olpn, llpn;
if (!participant->principal) {
wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1407,46 +1427,6 @@
if (body->ptx)
wpa_printf(MSG_WARNING, "KaY: peer's plain tx are TRUE");
-
- /* check latest key is valid */
- if (body->ltx || body->lrx) {
- found = FALSE;
- os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
- ki.kn = be_to_host32(body->lkn);
- dl_list_for_each(sa_key, &participant->sak_list,
- struct data_key, list) {
- if (is_ki_equal(&sa_key->key_identifier, &ki)) {
- found = TRUE;
- break;
- }
- }
- if (!found) {
- wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
- return -1;
- }
- if (os_memcmp(participant->lki.mi, body->lsrv_mi,
- sizeof(participant->lki.mi)) == 0 &&
- be_to_host32(body->lkn) == participant->lki.kn &&
- body->lan == participant->lan) {
- peer->sak_used = TRUE;
- }
- if (body->ltx && peer->is_key_server) {
- ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
- }
- }
-
- /* check old key is valid (but only if we remember our old key) */
- if (participant->oki.kn != 0 && (body->otx || body->orx)) {
- if (os_memcmp(participant->oki.mi, body->osrv_mi,
- sizeof(participant->oki.mi)) != 0 ||
- be_to_host32(body->okn) != participant->oki.kn ||
- body->oan != participant->oan) {
- wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
- return -1;
- }
- }
-
/* TODO: how to set the MACsec hardware when delay_protect is true */
if (body->delay_protect &&
(!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
@@ -1455,65 +1435,132 @@
return -1;
}
- /* check all live peer have used the sak for receiving sa */
- all_receiving = TRUE;
- dl_list_for_each(peer, &participant->live_peers,
- struct ieee802_1x_kay_peer, list) {
- if (!peer->sak_used) {
- all_receiving = FALSE;
- break;
- }
- }
- if (all_receiving) {
- participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
+ olpn = be_to_host32(body->olpn);
+ llpn = be_to_host32(body->llpn);
+
+ /* Our most recent distributed key should be the first in the list.
+ * If it doesn't exist then we can't really do anything.
+ * Be lenient and don't return error here as there are legitimate cases
+ * where this can happen such as when a new participant joins the CA and
+ * the first frame it receives can have a SAKuse but not distSAK.
+ */
+ sa_key = dl_list_first(&participant->sak_list, struct data_key, list);
+ if (!sa_key) {
+ wpa_printf(MSG_INFO,
+ "KaY: We don't have a latest distributed key - ignore SAK use");
+ return 0;
}
- /* if I'm key server, and detects peer member pn exhaustion, rekey. */
- lpn = be_to_host32(body->llpn);
- if (lpn > kay->pn_exhaustion) {
- if (participant->is_key_server) {
- participant->new_sak = TRUE;
- wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
- }
+ /* The peer's most recent key will be the "latest key" if it is present
+ * otherwise it will be the "old key" if in the RETIRE state.
+ */
+ if (body->lrx) {
+ os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->lkn);
+ lpn = llpn;
+ } else {
+ os_memcpy(ki.mi, body->osrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->okn);
+ lpn = olpn;
}
- if (sa_key)
- sa_key->next_pn = lpn;
- found = FALSE;
- dl_list_for_each(rxsc, &participant->rxsc_list, struct receive_sc,
- list) {
- dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa,
- list) {
- if (sa_key && rxsa->pkey == sa_key) {
- found = TRUE;
+ /* If the most recent distributed keys don't agree then someone is out
+ * of sync. Perhaps non key server hasn't processed the most recent
+ * distSAK yet and the key server is processing an old packet after it
+ * has done distSAK. Be lenient and don't return error in this
+ * particular case; otherwise, the key server will reset its MI and
+ * cause a traffic disruption which is really undesired for a simple
+ * timing issue.
+ */
+ if (!is_ki_equal(&sa_key->key_identifier, &ki)) {
+ wpa_printf(MSG_INFO,
+ "KaY: Distributed keys don't match - ignore SAK use");
+ return 0;
+ }
+ sa_key->next_pn = lpn;
+
+ /* The key server must check that all peers are using the most recent
+ * distributed key. Non key servers must check if the key server is
+ * transmitting.
+ */
+ if (participant->is_key_server) {
+ struct ieee802_1x_kay_peer *peer_iter;
+ Boolean all_receiving = TRUE;
+
+ /* Distributed keys are equal from above comparison. */
+ peer->sak_used = TRUE;
+
+ dl_list_for_each(peer_iter, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer_iter->sak_used) {
+ all_receiving = FALSE;
break;
}
}
- if (found)
- break;
- }
- if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
- return -1;
+ if (all_receiving) {
+ participant->to_dist_sak = FALSE;
+ ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+ } else if (peer->is_key_server) {
+ if (body->ltx) {
+ ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
}
+ /* If I'm key server, and detects peer member PN exhaustion, rekey.
+ * We only need to check the PN of the most recent distributed key. This
+ * could be the peer's "latest" or "old" key depending on its current
+ * state. If both "old" and "latest" keys are present then the "old" key
+ * has already been exhausted.
+ */
+ if (participant->is_key_server && lpn > kay->pn_exhaustion) {
+ participant->new_sak = TRUE;
+ wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
+ }
+
+ /* Get the associated RX SAs of the keys for delay protection since both
+ * can be in use. Delay protect window (communicated via MKA) is tighter
+ * than SecY's current replay protect window, so tell SecY the new (and
+ * higher) lpn.
+ */
if (body->delay_protect) {
- secy_get_receive_lowest_pn(participant->kay, rxsa);
- if (lpn > rxsa->lowest_pn) {
- /* Delay protect window (communicated via MKA) is
- * tighter than SecY's current replay protect window,
- * so tell SecY the new (and higher) lpn. */
- rxsa->lowest_pn = lpn;
- secy_set_receive_lowest_pn(participant->kay, rxsa);
- wpa_printf(MSG_DEBUG, "KaY: update lpn =0x%x", lpn);
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
+ Boolean found = FALSE;
+
+ dl_list_for_each(rxsc, &participant->rxsc_list,
+ struct receive_sc, list) {
+ dl_list_for_each(rxsa, &rxsc->sa_list,
+ struct receive_sa, list) {
+ if (sa_key && rxsa->pkey == sa_key) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ break;
}
- /* FIX: Delay protection for olpn not implemented.
- * Note that Old Key is only active for MKA_SAK_RETIRE_TIME
- * (3 seconds) and delay protection does allow PN's within
- * a 2 seconds window, so olpn would be a lot of work for
- * just 1 second's worth of protection. */
+ if (found) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay,
+ rxsa);
+ wpa_printf(MSG_DEBUG,
+ "KaY: update dist LPN=0x%x", lpn);
+ }
+ }
+
+ /* FIX: Delay protection for the SA being replaced is not
+ * implemented. Note that this key will be active for at least
+ * MKA_SAK_RETIRE_TIME (3 seconds) but could be longer depending
+ * on how long it takes to get from RECEIVE to TRANSMITTING or
+ * if going via ABANDON. Delay protection does allow PNs within
+ * a 2 second window, so getting PN would be a lot of work for
+ * just 1 second's worth of protection.
+ */
}
return 0;
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 1b605c7..c17e53b 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -161,143 +161,10 @@
*/
int num_sess;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - The D-H group assigned for EAP-pwd
- *
- * If EAP-pwd is not used it can be set to zero.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
struct dl_list erp_keys; /* struct eap_server_erp_key */
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -349,11 +216,6 @@
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -367,6 +229,8 @@
#ifdef CONFIG_SQLITE
sqlite3 *db;
#endif /* CONFIG_SQLITE */
+
+ const struct eap_config *eap_cfg;
};
@@ -617,7 +481,7 @@
#ifdef CONFIG_TESTING_OPTIONS
static void radius_server_testing_options_tls(struct radius_session *sess,
const char *tls,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
int test = atoi(tls);
@@ -662,7 +526,7 @@
#endif /* CONFIG_TESTING_OPTIONS */
static void radius_server_testing_options(struct radius_session *sess,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
#ifdef CONFIG_TESTING_OPTIONS
const char *pos;
@@ -705,7 +569,7 @@
size_t user_len, id_len;
int res;
struct radius_session *sess;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
struct eap_user *tmp;
RADIUS_DEBUG("Creating a new session");
@@ -723,7 +587,7 @@
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
#ifdef CONFIG_ERP
- if (res != 0 && data->erp) {
+ if (res != 0 && data->eap_cfg->erp) {
char *username;
username = os_zalloc(user_len + 1);
@@ -782,33 +646,10 @@
srv_log(sess, "New session created");
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.ssl_ctx = data->ssl_ctx;
- eap_conf.msg_ctx = data->msg_ctx;
- eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
- eap_conf.backend_auth = TRUE;
- eap_conf.eap_server = 1;
- eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = data->eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
- eap_conf.eap_fast_prov = data->eap_fast_prov;
- eap_conf.pac_key_lifetime = data->pac_key_lifetime;
- eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
- eap_conf.eap_teap_auth = data->eap_teap_auth;
- eap_conf.eap_teap_pac_no_inner = data->eap_teap_pac_no_inner;
- eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
- eap_conf.tnc = data->tnc;
- eap_conf.wps = data->wps;
- eap_conf.pwd_group = data->pwd_group;
- eap_conf.server_id = (const u8 *) data->server_id;
- eap_conf.server_id_len = os_strlen(data->server_id);
- eap_conf.erp = data->erp;
- eap_conf.tls_session_lifetime = data->tls_session_lifetime;
- eap_conf.tls_flags = data->tls_flags;
- radius_server_testing_options(sess, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ radius_server_testing_options(sess, &eap_sess);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
- &eap_conf);
+ data->eap_cfg, &eap_sess);
if (sess->eap == NULL) {
RADIUS_DEBUG("Failed to initialize EAP state machine for the "
"new session");
@@ -2360,75 +2201,52 @@
if (data == NULL)
return NULL;
+ data->eap_cfg = conf->eap_cfg;
data->auth_sock = -1;
data->acct_sock = -1;
dl_list_init(&data->erp_keys);
os_get_reltime(&data->start_time);
data->conf_ctx = conf->conf_ctx;
- data->eap_sim_db_priv = conf->eap_sim_db_priv;
- data->ssl_ctx = conf->ssl_ctx;
- data->msg_ctx = conf->msg_ctx;
+ conf->eap_cfg->backend_auth = TRUE;
+ conf->eap_cfg->eap_server = 1;
data->ipv6 = conf->ipv6;
- if (conf->pac_opaque_encr_key) {
- data->pac_opaque_encr_key = os_malloc(16);
- if (data->pac_opaque_encr_key) {
- os_memcpy(data->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (data->eap_fast_a_id) {
- os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- data->eap_fast_prov = conf->eap_fast_prov;
- data->pac_key_lifetime = conf->pac_key_lifetime;
- data->pac_key_refresh_time = conf->pac_key_refresh_time;
- data->eap_teap_auth = conf->eap_teap_auth;
- data->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
data->get_eap_user = conf->get_eap_user;
- data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- data->tnc = conf->tnc;
- data->wps = conf->wps;
- data->pwd_group = conf->pwd_group;
- data->server_id = conf->server_id;
if (conf->eap_req_id_text) {
data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
- if (data->eap_req_id_text) {
- os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
- conf->eap_req_id_text_len);
- data->eap_req_id_text_len = conf->eap_req_id_text_len;
- }
+ if (!data->eap_req_id_text)
+ goto fail;
+ os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
+ conf->eap_req_id_text_len);
+ data->eap_req_id_text_len = conf->eap_req_id_text_len;
}
- data->erp = conf->erp;
data->erp_domain = conf->erp_domain;
- data->tls_session_lifetime = conf->tls_session_lifetime;
- data->tls_flags = conf->tls_flags;
if (conf->subscr_remediation_url) {
data->subscr_remediation_url =
os_strdup(conf->subscr_remediation_url);
+ if (!data->subscr_remediation_url)
+ goto fail;
}
data->subscr_remediation_method = conf->subscr_remediation_method;
- if (conf->hs20_sim_provisioning_url)
+ if (conf->hs20_sim_provisioning_url) {
data->hs20_sim_provisioning_url =
os_strdup(conf->hs20_sim_provisioning_url);
+ if (!data->hs20_sim_provisioning_url)
+ goto fail;
+ }
- if (conf->t_c_server_url)
+ if (conf->t_c_server_url) {
data->t_c_server_url = os_strdup(conf->t_c_server_url);
+ if (!data->t_c_server_url)
+ goto fail;
+ }
#ifdef CONFIG_SQLITE
if (conf->sqlite_file) {
if (sqlite3_open(conf->sqlite_file, &data->db)) {
RADIUS_ERROR("Could not open SQLite file '%s'",
conf->sqlite_file);
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
}
#endif /* CONFIG_SQLITE */
@@ -2442,8 +2260,7 @@
conf->ipv6);
if (data->clients == NULL) {
wpa_printf(MSG_ERROR, "No RADIUS clients configured");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
#ifdef CONFIG_IPV6
@@ -2454,14 +2271,12 @@
data->auth_sock = radius_server_open_socket(conf->auth_port);
if (data->auth_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->auth_sock,
radius_server_receive_auth,
data, NULL)) {
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (conf->acct_port) {
@@ -2474,20 +2289,20 @@
data->acct_sock = radius_server_open_socket(conf->acct_port);
if (data->acct_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->acct_sock,
radius_server_receive_acct,
- data, NULL)) {
- radius_server_deinit(data);
- return NULL;
- }
+ data, NULL))
+ goto fail;
} else {
data->acct_sock = -1;
}
return data;
+fail:
+ radius_server_deinit(data);
+ return NULL;
}
@@ -2530,9 +2345,6 @@
radius_server_free_clients(data, data->clients);
- os_free(data->pac_opaque_encr_key);
- os_free(data->eap_fast_a_id);
- os_free(data->eap_fast_a_id_info);
os_free(data->eap_req_id_text);
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 88c22db..43192e5 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -51,141 +51,8 @@
*/
void *conf_ctx;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - EAP-pwd D-H group
- *
- * This is used to select which D-H group to use with EAP-pwd.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -225,11 +92,6 @@
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -239,6 +101,8 @@
char *hs20_sim_provisioning_url;
char *t_c_server_url;
+
+ struct eap_config *eap_cfg;
};
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index c2d81f2..eea0efb 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -8,7 +8,6 @@
include ../lib.rules
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_TDLS
CFLAGS += -DCONFIG_WNM
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index c6d0298..ace0b6a 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -655,51 +655,51 @@
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 */
@@ -1051,7 +1051,6 @@
}
-#ifdef CONFIG_IEEE80211W
static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
const struct wpa_igtk_kde *igtk,
int wnm_sleep)
@@ -1118,13 +1117,11 @@
return 0;
}
-#endif /* CONFIG_IEEE80211W */
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
-#ifdef CONFIG_IEEE80211W
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
@@ -1142,9 +1139,6 @@
}
return 0;
-#else /* CONFIG_IEEE80211W */
- return 0;
-#endif /* CONFIG_IEEE80211W */
}
@@ -1371,6 +1365,16 @@
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)
@@ -1455,7 +1459,6 @@
"WPA: GTK IE in unencrypted key data");
goto failed;
}
-#ifdef CONFIG_IEEE80211W
if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: IGTK KDE in unencrypted key data");
@@ -1471,7 +1474,6 @@
(unsigned long) ie.igtk_len);
goto failed;
}
-#endif /* CONFIG_IEEE80211W */
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
@@ -2294,9 +2296,7 @@
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -2324,7 +2324,6 @@
}
} else
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
!wpa_use_akm_defined(sm->key_mgmt)) {
@@ -2333,11 +2332,9 @@
"negotiated AES-128-CMAC");
goto out;
}
- } else
-#endif /* CONFIG_IEEE80211W */
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
- !wpa_use_akm_defined(sm->key_mgmt) &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
"descriptor version (%d) is not 2", ver);
@@ -2480,12 +2477,10 @@
case WPA_KEY_MGMT_FT_PSK:
return RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
case WPA_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_CCKM:
return (sm->proto == WPA_PROTO_RSN ?
RSN_AUTH_KEY_MGMT_CCKM:
@@ -2677,8 +2672,10 @@
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
@@ -2768,10 +2765,8 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
}
#ifdef CONFIG_TDLS
@@ -3043,11 +3038,9 @@
case WPA_PARAM_KEY_MGMT:
sm->key_mgmt = value;
break;
-#ifdef CONFIG_IEEE80211W
case WPA_PARAM_MGMT_GROUP:
sm->mgmt_group_cipher = value;
break;
-#endif /* CONFIG_IEEE80211W */
case WPA_PARAM_RSN_ENABLED:
sm->rsn_enabled = value;
break;
@@ -3057,6 +3050,9 @@
case WPA_PARAM_OCV:
sm->ocv = value;
break;
+ case WPA_PARAM_SAE_PWE:
+ sm->sae_pwe = value;
+ break;
default:
break;
}
@@ -3235,6 +3231,83 @@
/**
+ * 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)
@@ -3303,6 +3376,39 @@
/**
+ * 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
@@ -3375,10 +3481,8 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
@@ -3452,14 +3556,12 @@
return -1;
}
forced_memzero(&gd, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
const struct wpa_igtk_kde *igtk;
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -4019,10 +4121,10 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
wpabuf_put_le16(buf, capab);
@@ -4062,13 +4164,11 @@
WPA_PMK_NAME_LEN);
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
/* Management Group Cipher Suite */
pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = ((u8 *) wpabuf_put(buf, 0) - (u8 *) rsnie) - 2;
return 0;
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 @@
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 @@
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 @@
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 46ffdca..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 @@
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;
@@ -246,13 +250,10 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256 ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
@@ -266,7 +267,6 @@
os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
pos += WPA_PMK_NAME_LEN;
-#ifdef CONFIG_IEEE80211W
/* Management Group Cipher Suite */
switch (sm->mgmt_group_cipher) {
case WPA_CIPHER_AES_128_CMAC:
@@ -286,7 +286,6 @@
pos += RSN_SELECTOR_LEN;
break;
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = (pos - (u8 *) rsnie) - 2;
@@ -364,6 +363,13 @@
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
@@ -375,14 +381,18 @@
* 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;
@@ -598,6 +608,12 @@
return -1;
}
+ if (sm->mfp == 2 && !(parse.rsn_capab & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_INFO,
+ "FT: Target AP does not support PMF, but local configuration requires that");
+ return -1;
+ }
+
os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
@@ -767,7 +783,6 @@
}
-#ifdef CONFIG_IEEE80211W
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
size_t igtk_elem_len)
{
@@ -835,7 +850,6 @@
return 0;
}
-#endif /* CONFIG_IEEE80211W */
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
@@ -962,6 +976,8 @@
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",
@@ -982,6 +998,8 @@
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;
@@ -1018,10 +1036,8 @@
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
return -1;
-#ifdef CONFIG_IEEE80211W
if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
if (sm->set_ptk_after_assoc) {
wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index d86734b..2a43342 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -31,10 +31,8 @@
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
struct wpa_gtk gtk;
struct wpa_gtk gtk_wnm_sleep;
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
-#endif /* CONFIG_IEEE80211W */
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -87,11 +85,14 @@
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 ae9f4ca..03c0d7e 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -168,12 +168,10 @@
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -217,12 +215,10 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
if (sm->mfp == 2)
capab |= WPA_CAPABILITY_MFPR;
-#endif /* CONFIG_IEEE80211W */
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
@@ -237,7 +233,6 @@
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) {
/* PMKID Count */
@@ -250,7 +245,6 @@
mgmt_group_cipher));
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
hdr->len = (pos - rsn_ie) - 2;
@@ -348,261 +342,23 @@
}
-/**
- * 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;
+ u8 *pos = rsnxe;
- if (pos[1] < 4) {
- wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
- pos[1]);
- return 1;
- }
+ 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 */
- 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;
-}
+ if (rsnxe_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);
-/**
- * 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;
- }
-
-#ifdef CONFIG_IEEE80211W
- 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;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#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 + 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;
-}
-
-
-/**
- * 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]);
- }
- }
-
- return ret;
+ return pos - rsnxe;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 9d53973..6dc6cf5 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -11,56 +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;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
- 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/common.h b/src/utils/common.h
index 1741145..833469a 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -344,6 +344,9 @@
#ifndef ETH_P_OUI
#define ETH_P_OUI 0x88B7
#endif /* ETH_P_OUI */
+#ifndef ETH_P_8021Q
+#define ETH_P_8021Q 0x8100
+#endif /* ETH_P_8021Q */
#ifdef __GNUC__
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 @@
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\u%04x",
- data[i]);
+ (unsigned char) data[i]);
}
break;
}
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 474c8a3..feade6e 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -25,10 +25,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index b56bab2..494bf4c 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -51,10 +51,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
diff --git a/src/utils/trace.c b/src/utils/trace.c
index e0b5b0b..4084343 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -186,7 +186,7 @@
if (abfd == NULL)
return;
- data.pc = (bfd_hostptr_t) (pc - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -227,7 +227,7 @@
if (abfd == NULL)
return NULL;
- data.pc = (bfd_hostptr_t) (pc - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -299,7 +299,7 @@
for (i = 0; i < btrace_num; i++) {
struct bfd_data data;
- data.pc = (bfd_hostptr_t) (btrace_res[i] - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) btrace_res[i] - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 1fe0b7d..c94c439 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -305,7 +305,6 @@
#define HOSTAPD_MODULE_RADIUS 0x00000004
#define HOSTAPD_MODULE_WPA 0x00000008
#define HOSTAPD_MODULE_DRIVER 0x00000010
-#define HOSTAPD_MODULE_IAPP 0x00000020
#define HOSTAPD_MODULE_MLME 0x00000040
enum hostapd_logger_level {
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 @@
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 @@
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 @@
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 @@
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/eap-aka-peer/Makefile b/tests/fuzzing/eap-aka-peer/Makefile
deleted file mode 100644
index d1a4cd3..0000000
--- a/tests/fuzzing/eap-aka-peer/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-all: eap-aka-peer
-include ../rules.include
-
-CFLAGS += -DIEEE8021X_EAPOL
-CFLAGS += -DCONFIG_USIM_SIMULATOR
-
-OBJS += $(SRC)/eap_peer/eap_aka.o
-OBJS += $(SRC)/eap_common/eap_sim_common.o
-OBJS += $(SRC)/eap_common/eap_common.o
-LIBS += $(SRC)/crypto/libcrypto.a
-LIBS += $(SRC)/utils/libutils.a
-
-eap-aka-peer: eap-aka-peer.o $(OBJS) $(LIBS)
- $(Q)$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
- @$(E) " LD " $@
-
-clean:
- $(MAKE) -C $(SRC) clean
- rm -f eap-aka-peer *~ *.o *.d ../*~ ../*.o ../*.d
-
--include $(OBJS:%.o=%.d)
diff --git a/tests/fuzzing/eap-aka-peer/corpus/server.msg b/tests/fuzzing/eap-aka-peer/corpus/server.msg
deleted file mode 100644
index 6484391..0000000
--- a/tests/fuzzing/eap-aka-peer/corpus/server.msg
+++ /dev/null
Binary files differ
diff --git a/tests/fuzzing/eap-aka-peer/eap-aka-peer.c b/tests/fuzzing/eap-aka-peer/eap-aka-peer.c
deleted file mode 100644
index e36c6ca..0000000
--- a/tests/fuzzing/eap-aka-peer/eap-aka-peer.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * EAP-AKA peer fuzzer
- * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "eap_peer/eap_methods.h"
-#include "eap_peer/eap_config.h"
-#include "eap_peer/eap_i.h"
-#include "../fuzzer-common.h"
-
-int eap_peer_sim_register(void);
-
-struct eap_method * registered_eap_method = NULL;
-
-
-struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
-{
- struct eap_method *eap;
- eap = os_zalloc(sizeof(*eap));
- if (!eap)
- return NULL;
- eap->version = version;
- eap->vendor = vendor;
- eap->method = method;
- eap->name = name;
- return eap;
-}
-
-
-int eap_peer_method_register(struct eap_method *method)
-{
- registered_eap_method = method;
- return 0;
-}
-
-
-static struct eap_peer_config eap_aka_config = {
- .identity = (u8 *) "0232010000000000",
- .identity_len = 16,
- .password = (u8 *) "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
- .password_len = 78,
-};
-
-struct eap_peer_config * eap_get_config(struct eap_sm *sm)
-{
- return &eap_aka_config;
-}
-
-
-const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
-{
- static const char *id = "0232010000000000";
-
- *len = os_strlen(id);
- return (const u8 *) id;
-}
-
-
-const char * eap_get_config_phase1(struct eap_sm *sm)
-{
- return NULL;
-}
-
-
-void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
-{
-}
-
-
-void eap_sm_request_identity(struct eap_sm *sm)
-{
-}
-
-
-void eap_sm_request_sim(struct eap_sm *sm, const char *req)
-{
-}
-
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- const u8 *pos, *end;
- struct eap_sm *sm;
- void *priv;
- struct eap_method_ret ret;
-
- wpa_fuzzer_set_debug_level();
-
- eap_peer_aka_register();
- sm = os_zalloc(sizeof(*sm));
- if (!sm)
- return 0;
- priv = registered_eap_method->init(sm);
- os_memset(&ret, 0, sizeof(ret));
-
- pos = data;
- end = pos + size;
-
- while (end - pos > 2) {
- u16 flen;
- struct wpabuf *buf, *req;
-
- flen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < flen)
- break;
- req = wpabuf_alloc_copy(pos, flen);
- if (!req)
- break;
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - request", req);
- buf = registered_eap_method->process(sm, priv, &ret, req);
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - local response", buf);
- wpabuf_free(req);
- wpabuf_free(buf);
- pos += flen;
- }
-
- registered_eap_method->deinit(sm, priv);
- os_free(registered_eap_method);
- os_free(sm);
-
- return 0;
-}
diff --git a/tests/fuzzing/eap-sim-peer/Makefile b/tests/fuzzing/eap-sim-peer/Makefile
deleted file mode 100644
index 302717e..0000000
--- a/tests/fuzzing/eap-sim-peer/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-all: eap-sim-peer
-include ../rules.include
-
-CFLAGS += -DIEEE8021X_EAPOL
-CFLAGS += -DCONFIG_SIM_SIMULATOR
-
-OBJS += $(SRC)/eap_peer/eap_sim.o
-OBJS += $(SRC)/eap_common/eap_sim_common.o
-OBJS += $(SRC)/eap_common/eap_common.o
-LIBS += $(SRC)/crypto/libcrypto.a
-LIBS += $(SRC)/utils/libutils.a
-
-eap-sim-peer: eap-sim-peer.o $(OBJS) $(LIBS)
- $(Q)$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
- @$(E) " LD " $@
-
-clean:
- $(MAKE) -C $(SRC) clean
- rm -f eap-sim-peer *~ *.o *.d ../*~ ../*.o ../*.d
-
--include $(OBJS:%.o=%.d)
diff --git a/tests/fuzzing/eap-sim-peer/corpus/server.msg b/tests/fuzzing/eap-sim-peer/corpus/server.msg
deleted file mode 100644
index adb9f6c..0000000
--- a/tests/fuzzing/eap-sim-peer/corpus/server.msg
+++ /dev/null
Binary files differ
diff --git a/tests/fuzzing/eap-sim-peer/eap-sim-peer.c b/tests/fuzzing/eap-sim-peer/eap-sim-peer.c
deleted file mode 100644
index ce701f3..0000000
--- a/tests/fuzzing/eap-sim-peer/eap-sim-peer.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * EAP-SIM peer fuzzer
- * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "eap_peer/eap_methods.h"
-#include "eap_peer/eap_config.h"
-#include "eap_peer/eap_i.h"
-#include "../fuzzer-common.h"
-
-int eap_peer_sim_register(void);
-
-struct eap_method * registered_eap_method = NULL;
-
-
-struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
-{
- struct eap_method *eap;
- eap = os_zalloc(sizeof(*eap));
- if (!eap)
- return NULL;
- eap->version = version;
- eap->vendor = vendor;
- eap->method = method;
- eap->name = name;
- return eap;
-}
-
-
-int eap_peer_method_register(struct eap_method *method)
-{
- registered_eap_method = method;
- return 0;
-}
-
-
-static struct eap_peer_config eap_sim_config = {
- .identity = (u8 *) "1232010000000000",
- .identity_len = 16,
- .password = (u8 *) "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
- .password_len = 65,
-};
-
-struct eap_peer_config * eap_get_config(struct eap_sm *sm)
-{
- return &eap_sim_config;
-}
-
-
-const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
-{
- static const char *id = "1232010000000000";
-
- *len = os_strlen(id);
- return (const u8 *) id;
-}
-
-
-void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
-{
-}
-
-
-void eap_sm_request_identity(struct eap_sm *sm)
-{
-}
-
-
-void eap_sm_request_sim(struct eap_sm *sm, const char *req)
-{
-}
-
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- const u8 *pos, *end;
- struct eap_sm *sm;
- void *priv;
- struct eap_method_ret ret;
-
- wpa_fuzzer_set_debug_level();
-
- eap_peer_sim_register();
- sm = os_zalloc(sizeof(*sm));
- if (!sm)
- return 0;
- priv = registered_eap_method->init(sm);
- os_memset(&ret, 0, sizeof(ret));
-
- pos = data;
- end = pos + size;
-
- while (end - pos > 2) {
- u16 flen;
- struct wpabuf *buf, *req;
-
- flen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < flen)
- break;
- req = wpabuf_alloc_copy(pos, flen);
- if (!req)
- break;
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - request", req);
- buf = registered_eap_method->process(sm, priv, &ret, req);
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - local response", buf);
- wpabuf_free(req);
- wpabuf_free(buf);
- pos += flen;
- }
-
- registered_eap_method->deinit(sm, priv);
- os_free(registered_eap_method);
- os_free(sm);
-
- return 0;
-}
diff --git a/tests/test-eapol.c b/tests/test-eapol.c
deleted file mode 100644
index 57f2118..0000000
--- a/tests/test-eapol.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Testing tool for EAPOL-Key Supplicant/Authenticator routines
- * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "rsn_supp/wpa.h"
-#include "ap/wpa_auth.h"
-
-
-struct wpa {
- enum { AUTH, SUPP } test_peer;
- enum { READ, WRITE } test_oper;
- FILE *f;
- int wpa1;
-
- u8 auth_addr[ETH_ALEN];
- u8 supp_addr[ETH_ALEN];
- u8 psk[PMK_LEN];
-
- /* from authenticator */
- u8 *auth_eapol;
- size_t auth_eapol_len;
-
- /* from supplicant */
- u8 *supp_eapol;
- size_t supp_eapol_len;
-
- struct wpa_sm *supp;
- struct wpa_authenticator *auth_group;
- struct wpa_state_machine *auth;
-
- u8 supp_ie[80];
- size_t supp_ie_len;
-
- int key_request_done;
- int key_request_done1;
- int auth_sent;
-};
-
-
-const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
-
-
-static int auth_read_msg(struct wpa *wpa);
-static void supp_eapol_key_request(void *eloop_data, void *user_ctx);
-
-
-static void usage(void) {
- wpa_printf(MSG_INFO,
- "usage: test-eapol <auth/supp> <read/write> <file>");
- exit(-1);
-}
-
-
-static void write_msg(FILE *f, const u8 *msg, size_t msg_len)
-{
- u8 len[2];
-
- wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
- (unsigned int) msg_len);
- WPA_PUT_BE16(len, msg_len);
- fwrite(len, 2, 1, f);
- fwrite(msg, msg_len, 1, f);
-}
-
-
-static u8 * read_msg(FILE *f, size_t *ret_len)
-{
- u8 len[2];
- u16 msg_len;
- u8 *msg;
-
- if (fread(len, 2, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
- eloop_terminate();
- return NULL;
- }
- msg_len = WPA_GET_BE16(len);
-
- msg = os_malloc(msg_len);
- if (!msg)
- return NULL;
- if (msg_len > 0 && fread(msg, msg_len, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
- msg_len);
- os_free(msg);
- eloop_terminate();
- return NULL;
- }
- wpa_hexdump(MSG_DEBUG, "TEST: Read message from file", msg, msg_len);
-
- *ret_len = msg_len;
- return msg;
-}
-
-
-static int supp_get_bssid(void *ctx, u8 *bssid)
-{
- struct wpa *wpa = ctx;
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
- os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
- return 0;
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
-}
-
-
-static void auth_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
- wpa->auth_sent = 0;
- wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
- wpa->supp_eapol_len);
- if (!wpa->auth_sent && wpa->test_peer == SUPP &&
- wpa->test_oper == READ) {
- /* Speed up process by not going through retransmit timeout */
- wpa_printf(MSG_DEBUG,
- "AUTH: No response was sent - process next message");
- auth_read_msg(wpa);
- }
- if (wpa->wpa1 && wpa->key_request_done && !wpa->key_request_done1) {
- wpa->key_request_done1 = 1;
- eloop_register_timeout(0, 0, supp_eapol_key_request,
- wpa, NULL);
- }
-
-}
-
-
-static void supp_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
- wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
- wpa->auth_eapol_len);
-}
-
-
-static int supp_read_msg(struct wpa *wpa)
-{
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = read_msg(wpa->f, &wpa->auth_eapol_len);
- if (!wpa->auth_eapol)
- return -1;
- eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
- return 0;
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
- size_t len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
-
- if (wpa->test_peer == SUPP && wpa->test_oper == WRITE)
- write_msg(wpa->f, buf, len);
-
- if (wpa->test_peer == AUTH && wpa->test_oper == READ)
- return supp_read_msg(wpa);
-
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = os_malloc(len);
- if (!wpa->supp_eapol)
- return -1;
- os_memcpy(wpa->supp_eapol, buf, len);
- wpa->supp_eapol_len = len;
- eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
- u16 data_len, size_t *msg_len, void **data_pos)
-{
- struct ieee802_1x_hdr *hdr;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
- __func__, type, data_len);
-
- *msg_len = sizeof(*hdr) + data_len;
- hdr = os_malloc(*msg_len);
- if (hdr == NULL)
- return NULL;
-
- hdr->version = 2;
- hdr->type = type;
- hdr->length = host_to_be16(data_len);
-
- if (data)
- os_memcpy(hdr + 1, data, data_len);
- else
- os_memset(hdr + 1, 0, data_len);
-
- if (data_pos)
- *data_pos = hdr + 1;
-
- return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
- struct wpa *wpa = ctx;
- const u8 *ie;
- size_t ielen;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-
- ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
- if (ie == NULL || ielen < 1)
- return -1;
- if (ie[0] == WLAN_EID_RSN)
- return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
- return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
-}
-
-
-static int supp_set_key(void *ctx, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
- "set_tx=%d)",
- __func__, alg, MAC2STR(addr), key_idx, set_tx);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
- return 0;
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
- int protection_type, int key_type)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
- "key_type=%d)",
- __func__, MAC2STR(addr), protection_type, key_type);
- return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-static void * supp_get_network_ctx(void *ctx)
-{
- return (void *) 1;
-}
-
-
-static void supp_deauthenticate(void *ctx, u16 reason_code)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(%d)", __func__, reason_code);
-}
-
-
-static enum wpa_states supp_get_state(void *ctx)
-{
- return WPA_COMPLETED;
-}
-
-
-static int supp_init(struct wpa *wpa)
-{
- struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
-
- if (!ctx)
- return -1;
-
- ctx->ctx = wpa;
- ctx->msg_ctx = wpa;
- ctx->set_state = supp_set_state;
- ctx->get_bssid = supp_get_bssid;
- ctx->ether_send = supp_ether_send;
- ctx->get_beacon_ie = supp_get_beacon_ie;
- ctx->alloc_eapol = supp_alloc_eapol;
- ctx->set_key = supp_set_key;
- ctx->mlme_setprotection = supp_mlme_setprotection;
- ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
- ctx->get_network_ctx = supp_get_network_ctx;
- ctx->deauthenticate = supp_deauthenticate;
- ctx->get_state = supp_get_state;
- wpa->supp = wpa_sm_init(ctx);
- if (!wpa->supp) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
- return -1;
- }
-
- wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
- if (wpa->wpa1) {
- wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 0);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_WPA);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
- WPA_CIPHER_TKIP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_TKIP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
- WPA_KEY_MGMT_PSK);
- } else {
- wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
- WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
- WPA_KEY_MGMT_PSK);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_MFP,
- MGMT_FRAME_PROTECTION_OPTIONAL);
- }
- wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN, NULL, NULL);
-
- wpa->supp_ie_len = sizeof(wpa->supp_ie);
- if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
- &wpa->supp_ie_len) < 0) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
- " failed");
- return -1;
- }
-
- wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
-
- return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
- const char *txt)
-{
- if (addr)
- wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
- MAC2STR(addr), txt);
- else
- wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static int auth_read_msg(struct wpa *wpa)
-{
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = read_msg(wpa->f, &wpa->supp_eapol_len);
- if (!wpa->supp_eapol)
- return -1;
- eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
- return 0;
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
- size_t data_len, int encrypt)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
- "encrypt=%d)",
- __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
- wpa->auth_sent = 1;
-
- if (wpa->test_peer == AUTH && wpa->test_oper == WRITE)
- write_msg(wpa->f, data, data_len);
-
- if (wpa->test_peer == SUPP && wpa->test_oper == READ)
- return auth_read_msg(wpa);
-
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = os_malloc(data_len);
- if (!wpa->auth_eapol)
- return -1;
- os_memcpy(wpa->auth_eapol, data, data_len);
- wpa->auth_eapol_len = data_len;
- eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr,
- const u8 *p2p_dev_addr, const u8 *prev_psk,
- size_t *psk_len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
- __func__, MAC2STR(addr), prev_psk);
- if (psk_len)
- *psk_len = PMK_LEN;
- if (prev_psk)
- return NULL;
- return wpa->psk;
-}
-
-
-static void supp_eapol_key_request(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "SUPP: EAPOL-Key Request trigger");
- if (wpa->test_peer == SUPP && wpa->test_oper == READ) {
- if (!eloop_is_timeout_registered(auth_eapol_rx, wpa, NULL))
- auth_read_msg(wpa);
- } else {
- wpa_sm_key_request(wpa->supp, 0, 1);
- }
-}
-
-
-static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key,
- size_t key_len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s (vlan_id=%d alg=%d idx=%d key_len=%d)",
- __func__, vlan_id, alg, idx, (int) key_len);
- if (addr)
- wpa_printf(MSG_DEBUG, "AUTH: addr=" MACSTR, MAC2STR(addr));
-
- if (alg != WPA_ALG_NONE && idx == 0 && key_len > 0 &&
- !wpa->key_request_done) {
- wpa_printf(MSG_DEBUG, "Test EAPOL-Key Request");
- wpa->key_request_done = 1;
- if (!wpa->wpa1)
- eloop_register_timeout(0, 0, supp_eapol_key_request,
- wpa, NULL);
- }
-
- return 0;
-}
-
-
-static int auth_init_group(struct wpa *wpa)
-{
- struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
-
- wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
- os_memset(&conf, 0, sizeof(conf));
- if (wpa->wpa1) {
- conf.wpa = 1;
- conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf.wpa_pairwise = WPA_CIPHER_TKIP;
- conf.wpa_group = WPA_CIPHER_TKIP;
- } else {
- conf.wpa = 2;
- conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
- conf.ieee80211w = 2;
- conf.group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
- }
- conf.eapol_version = 2;
- conf.wpa_group_update_count = 4;
- conf.wpa_pairwise_update_count = 4;
-
- os_memset(&cb, 0, sizeof(cb));
- cb.logger = auth_logger;
- cb.send_eapol = auth_send_eapol;
- cb.get_psk = auth_get_psk;
- cb.set_key = auth_set_key,
-
- wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb, wpa);
- if (!wpa->auth_group) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
- return -1;
- }
-
- return 0;
-}
-
-
-static int auth_init(struct wpa *wpa)
-{
- if (wpa->test_peer == AUTH && wpa->test_oper == READ)
- return supp_read_msg(wpa);
-
- wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
- if (!wpa->auth) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
- return -1;
- }
-
- if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
- wpa->supp_ie_len, NULL, 0, NULL, 0) !=
- WPA_IE_OK) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
- return -1;
- }
-
- wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
-
- wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
-
- return 0;
-}
-
-
-static void deinit(struct wpa *wpa)
-{
- wpa_auth_sta_deinit(wpa->auth);
- wpa_sm_deinit(wpa->supp);
- wpa_deinit(wpa->auth_group);
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = NULL;
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = NULL;
-}
-
-
-int main(int argc, char *argv[])
-{
- const char *file;
- int ret;
- struct wpa wpa;
-
- if (os_program_init())
- return -1;
-
- wpa_debug_level = 0;
- wpa_debug_show_keys = 1;
- os_memset(&wpa, 0, sizeof(wpa));
-
- if (argc < 4)
- usage();
-
- if (os_strcmp(argv[1], "auth") == 0) {
- wpa.test_peer = AUTH;
- } else if (os_strcmp(argv[1], "auth1") == 0) {
- wpa.test_peer = AUTH;
- wpa.wpa1 = 1;
- } else if (os_strcmp(argv[1], "supp") == 0) {
- wpa.test_peer = SUPP;
- } else if (os_strcmp(argv[1], "supp1") == 0) {
- wpa.test_peer = SUPP;
- wpa.wpa1 = 1;
- } else {
- usage();
- }
-
- if (os_strcmp(argv[2], "read") == 0)
- wpa.test_oper = READ;
- else if (os_strcmp(argv[2], "write") == 0)
- wpa.test_oper = WRITE;
- else
- usage();
-
- file = argv[3];
-
- wpa.f = fopen(file, wpa.test_oper == READ ? "r" : "w");
- if (!wpa.f)
- return -1;
-
- os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
- os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
- os_memset(wpa.psk, 0x44, PMK_LEN);
-
- if (eloop_init()) {
- wpa_printf(MSG_ERROR, "Failed to initialize event loop");
- goto fail;
- }
-
- if (auth_init_group(&wpa) < 0)
- goto fail;
-
- if (supp_init(&wpa) < 0)
- goto fail;
-
- if (auth_init(&wpa) < 0)
- goto fail;
-
- wpa_printf(MSG_DEBUG, "Starting eloop");
- eloop_run();
- wpa_printf(MSG_DEBUG, "eloop done");
-
- ret = 0;
-fail:
- deinit(&wpa);
- fclose(wpa.f);
-
- eloop_destroy();
-
- os_program_deinit();
-
- return ret;
-}
diff --git a/tests/test-json.c b/tests/test-json.c
deleted file mode 100644
index c7cb460..0000000
--- a/tests/test-json.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * JSON parser - test program
- * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "utils/includes.h"
-#include "utils/os.h"
-#include "utils/json.h"
-
-
-int main(int argc, char *argv[])
-{
- char *buf;
- size_t len;
- struct json_token *root;
-
- if (argc < 2)
- return -1;
-
- buf = os_readfile(argv[1], &len);
- if (!buf)
- return -1;
-
- root = json_parse(buf, len);
- os_free(buf);
- if (root) {
- size_t buflen = 10000;
-
- buf = os_zalloc(buflen);
- if (buf) {
- json_print_tree(root, buf, buflen);
- printf("%s\n", buf);
- os_free(buf);
- }
- json_free(root);
- } else {
- printf("JSON parsing failed\n");
- }
-
- return 0;
-}
diff --git a/tests/test-tls.c b/tests/test-tls.c
deleted file mode 100644
index 9941fb5..0000000
--- a/tests/test-tls.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Testing tool for TLSv1 client/server routines
- * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/tls.h"
-
-
-static void usage(void) {
- wpa_printf(MSG_INFO,
- "usage: test-tls <server/client> <read/write> <file>");
- exit(-1);
-}
-
-
-static void write_msg(FILE *f, struct wpabuf *msg)
-{
- u8 len[2];
-
- wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
- (unsigned int) wpabuf_len(msg));
- WPA_PUT_BE16(len, wpabuf_len(msg));
- fwrite(len, 2, 1, f);
- fwrite(wpabuf_head(msg), wpabuf_len(msg), 1, f);
-}
-
-
-static struct wpabuf * read_msg(FILE *f)
-{
- u8 len[2];
- u16 msg_len;
- struct wpabuf *msg;
-
- if (fread(len, 2, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
- return NULL;
- }
- msg_len = WPA_GET_BE16(len);
-
- msg = wpabuf_alloc(msg_len);
- if (!msg)
- return NULL;
- if (msg_len > 0 &&
- fread(wpabuf_put(msg, msg_len), msg_len, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
- msg_len);
- wpabuf_free(msg);
- return NULL;
- }
- wpa_hexdump_buf(MSG_DEBUG, "TEST: Read message from file", msg);
-
- return msg;
-}
-
-
-int main(int argc, char *argv[])
-{
- struct tls_config conf;
- void *tls_server, *tls_client;
- struct tls_connection_params params;
- struct tls_connection *conn_server = NULL, *conn_client = NULL;
- int ret = -1;
- struct wpabuf *in = NULL, *out = NULL, *appl;
- enum { SERVER, CLIENT } test_peer;
- enum { READ, WRITE } test_oper;
- const char *file;
- FILE *f;
-
- wpa_debug_level = 0;
- wpa_debug_show_keys = 1;
-
- if (argc < 4)
- usage();
-
- if (os_strcmp(argv[1], "server") == 0)
- test_peer = SERVER;
- else if (os_strcmp(argv[1], "client") == 0)
- test_peer = CLIENT;
- else
- usage();
-
- if (os_strcmp(argv[2], "read") == 0)
- test_oper = READ;
- else if (os_strcmp(argv[2], "write") == 0)
- test_oper = WRITE;
- else
- usage();
-
- file = argv[3];
-
- f = fopen(file, test_oper == READ ? "r" : "w");
- if (!f)
- return -1;
-
- os_memset(&conf, 0, sizeof(conf));
- tls_server = tls_init(&conf);
- tls_client = tls_init(&conf);
- if (!tls_server || !tls_client)
- goto fail;
-
- os_memset(¶ms, 0, sizeof(params));
- params.ca_cert = "hwsim/auth_serv/ca.pem";
- params.client_cert = "hwsim/auth_serv/server.pem";
- params.private_key = "hwsim/auth_serv/server.key";
- params.dh_file = "hwsim/auth_serv/dh.conf";
-
- if (tls_global_set_params(tls_server, ¶ms)) {
- wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
- goto fail;
- }
-
- conn_server = tls_connection_init(tls_server);
- conn_client = tls_connection_init(tls_client);
- if (!conn_server || !conn_client)
- goto fail;
-
- in = NULL;
- for (;;) {
- appl = NULL;
- if (test_peer == CLIENT && test_oper == READ)
- out = read_msg(f);
- else
- out = tls_connection_handshake(tls_client, conn_client,
- in, &appl);
- wpabuf_free(in);
- in = NULL;
- if (!out)
- goto fail;
- if (test_peer == CLIENT && test_oper == WRITE &&
- wpabuf_len(out) > 0)
- write_msg(f, out);
- if (!(test_peer == CLIENT && test_oper == READ) &&
- tls_connection_get_failed(tls_client, conn_client)) {
- wpa_printf(MSG_ERROR, "TLS handshake failed");
- goto fail;
- }
- if (((test_peer == CLIENT && test_oper == READ) ||
- tls_connection_established(tls_client, conn_client)) &&
- ((test_peer == SERVER && test_oper == READ) ||
- tls_connection_established(tls_server, conn_server)))
- break;
-
- appl = NULL;
- if (test_peer == SERVER && test_oper == READ)
- in = read_msg(f);
- else
- in = tls_connection_server_handshake(tls_server,
- conn_server,
- out, &appl);
- wpabuf_free(out);
- out = NULL;
- if (!in)
- goto fail;
- if (test_peer == SERVER && test_oper == WRITE)
- write_msg(f, in);
- if (!(test_peer == SERVER && test_oper == READ) &&
- tls_connection_get_failed(tls_server, conn_server)) {
- wpa_printf(MSG_ERROR, "TLS handshake failed");
- goto fail;
- }
- if (((test_peer == CLIENT && test_oper == READ) ||
- tls_connection_established(tls_client, conn_client)) &&
- ((test_peer == SERVER && test_oper == READ) ||
- tls_connection_established(tls_server, conn_server)))
- break;
- }
-
- wpabuf_free(in);
- in = wpabuf_alloc(100);
- if (!in)
- goto fail;
- wpabuf_put_str(in, "PING");
- wpabuf_free(out);
- if (test_peer == CLIENT && test_oper == READ)
- out = read_msg(f);
- else
- out = tls_connection_encrypt(tls_client, conn_client, in);
- wpabuf_free(in);
- in = NULL;
- if (!out)
- goto fail;
- if (test_peer == CLIENT && test_oper == WRITE)
- write_msg(f, out);
-
- if (!(test_peer == SERVER && test_oper == READ)) {
- in = tls_connection_decrypt(tls_server, conn_server, out);
- wpabuf_free(out);
- out = NULL;
- if (!in)
- goto fail;
- wpa_hexdump_buf(MSG_DEBUG, "Server decrypted ApplData", in);
- }
-
- wpabuf_free(in);
- in = wpabuf_alloc(100);
- if (!in)
- goto fail;
- wpabuf_put_str(in, "PONG");
- wpabuf_free(out);
- if (test_peer == SERVER && test_oper == READ)
- out = read_msg(f);
- else
- out = tls_connection_encrypt(tls_server, conn_server, in);
- wpabuf_free(in);
- in = NULL;
- if (!out)
- goto fail;
- if (test_peer == SERVER && test_oper == WRITE)
- write_msg(f, out);
-
- if (!(test_peer == CLIENT && test_oper == READ)) {
- in = tls_connection_decrypt(tls_client, conn_client, out);
- wpabuf_free(out);
- out = NULL;
- if (!in)
- goto fail;
- wpa_hexdump_buf(MSG_DEBUG, "Client decrypted ApplData", in);
- }
-
- ret = 0;
-fail:
- if (tls_server) {
- if (conn_server)
- tls_connection_deinit(tls_server, conn_server);
- tls_deinit(tls_server);
- }
- if (tls_client) {
- if (conn_client)
- tls_connection_deinit(tls_server, conn_client);
- tls_deinit(tls_client);
- }
- wpabuf_free(in);
- wpabuf_free(out);
- fclose(f);
-
- return ret;
-}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 3298f91..8fd2710 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -123,6 +123,7 @@
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
+OBJS += src/utils/ip_addr.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
@@ -228,8 +229,6 @@
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -240,25 +239,15 @@
ifdef CONFIG_OCV
L_CFLAGS += -DCONFIG_OCV
OBJS += src/common/ocv.c
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-L_CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -284,9 +273,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
@@ -301,7 +290,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -328,8 +316,6 @@
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -394,7 +380,6 @@
OBJS += hs20_supplicant.c
L_CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -461,7 +446,6 @@
ifdef CONFIG_ERP
L_CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -616,7 +600,6 @@
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -649,7 +632,6 @@
else
L_CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -689,6 +671,8 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
endif
ifdef CONFIG_EAP_PAX
@@ -728,15 +712,12 @@
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_PWD
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
CONFIG_IEEE8021X_EAPOL=y
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -753,7 +734,6 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -773,7 +753,6 @@
OBJS += src/wps/wps_registrar.c
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -890,7 +869,6 @@
OBJS += src/ap/utils.c
OBJS += src/ap/authsrv.c
OBJS += src/ap/ap_config.c
-OBJS += src/utils/ip_addr.c
OBJS += src/ap/sta_info.c
OBJS += src/ap/tkip_countermeasures.c
OBJS += src/ap/ap_mlme.c
@@ -959,8 +937,12 @@
ifdef CONFIG_DPP
OBJS += src/ap/dpp_hostapd.c
OBJS += src/ap/gas_query_ap.c
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += src/ap/gas_serv.c
endif
ifdef CONFIG_HS20
@@ -1064,7 +1046,6 @@
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -1079,7 +1060,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1142,7 +1122,6 @@
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1262,12 +1241,10 @@
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -1275,14 +1252,12 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
L_CFLAGS += -DCONFIG_OPENSSL_CMAC
else
AESOBJS += src/crypto/aes-omac1.c
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1375,7 +1350,6 @@
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -1397,6 +1371,9 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
SHA256OBJS += src/crypto/sha256-kdf.c
@@ -1410,7 +1387,6 @@
SHA256OBJS += src/crypto/sha512-kdf.c
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1663,9 +1639,6 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
OBJS_t += src/radius/radius.c
-ifndef CONFIG_AP
-OBJS_t += src/utils/ip_addr.c
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c
OBJS += $(CONFIG_MAIN).c
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 89119e7..f82e5e0 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,34 @@
ChangeLog for wpa_supplicant
+2019-08-07 - v2.9
+ * SAE changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * EAP-pwd changes
+ - disable use of groups using Brainpool curves
+ - allow the set of groups to be configured (eap_pwd_groups)
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * fixed FT-EAP initial mobility domain association using PMKSA caching
+ (disabled by default for backwards compatibility; can be enabled
+ with ft_eap_pmksa_caching=1)
+ * fixed a regression in OpenSSL 1.1+ engine loading
+ * added validation of RSNE in (Re)Association Response frames
+ * fixed DPP bootstrapping URI parser of channel list
+ * extended EAP-SIM/AKA fast re-authentication to allow use with FILS
+ * extended ca_cert_blob to support PEM format
+ * improved robustness of P2P Action frame scheduling
+ * added support for EAP-SIM/AKA using anonymous@realm identity
+ * fixed Hotspot 2.0 credential selection based on roaming consortium
+ to ignore credentials without a specific EAP method
+ * added experimental support for EAP-TEAP peer (RFC 7170)
+ * added experimental support for EAP-TLS peer with TLS v1.3
+ * fixed a regression in WMM parameter configuration for a TDLS peer
+ * fixed a regression in operation with drivers that offload 802.1X
+ 4-way handshake
+ * fixed an ECDH operation corner case with OpenSSL
+
2019-04-21 - v2.8
* SAE changes
- added support for SAE Password Identifier
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index f1384d5..a6329c0 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -103,6 +103,7 @@
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/bitfield.o
+OBJS += ../src/utils/ip_addr.o
OBJS += op_classes.o
OBJS += rrm.o
OBJS_p = wpa_passphrase.o
@@ -230,8 +231,6 @@
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -242,25 +241,15 @@
ifdef CONFIG_OCV
CFLAGS += -DCONFIG_OCV
OBJS += ../src/common/ocv.o
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R
OBJS += ../src/rsn_supp/wpa_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -286,9 +275,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
@@ -303,7 +292,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -330,8 +318,6 @@
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -404,7 +390,6 @@
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -458,7 +443,6 @@
ifdef CONFIG_ERP
CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -613,7 +597,6 @@
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -646,7 +629,6 @@
else
CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -686,6 +668,8 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
endif
ifdef CONFIG_EAP_PAX
@@ -725,8 +709,6 @@
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
@@ -736,7 +718,6 @@
endif
OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
CONFIG_IEEE8021X_EAPOL=y
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -753,7 +734,6 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -773,7 +753,6 @@
OBJS += ../src/wps/wps_registrar.o
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -871,7 +850,6 @@
NEED_AES_ENCBLOCK=y
NEED_AES_UNWRAP=y
NEED_AES_WRAP=y
-NEED_AES_OMAC1=y
OBJS += wpas_kay.o
OBJS += ../src/pae/ieee802_1x_cp.o
OBJS += ../src/pae/ieee802_1x_kay.o
@@ -907,7 +885,6 @@
OBJS += ../src/ap/utils.o
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ap_config.o
-OBJS += ../src/utils/ip_addr.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/tkip_countermeasures.o
OBJS += ../src/ap/ap_mlme.o
@@ -976,8 +953,12 @@
ifdef CONFIG_DPP
OBJS += ../src/ap/dpp_hostapd.o
OBJS += ../src/ap/gas_query_ap.o
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += ../src/ap/gas_serv.o
endif
ifdef CONFIG_HS20
@@ -1081,7 +1062,6 @@
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), wolfssl)
@@ -1112,7 +1092,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1176,7 +1155,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1256,7 +1234,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1342,12 +1319,10 @@
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += ../src/crypto/aes-siv.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += ../src/crypto/aes-ctr.o
@@ -1355,7 +1330,6 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
CFLAGS += -DCONFIG_OPENSSL_CMAC
@@ -1366,7 +1340,6 @@
endif
endif
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1475,7 +1448,6 @@
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1501,6 +1473,9 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += ../src/crypto/sha384-tlsprf.o
+endif
ifdef NEED_HMAC_SHA256_KDF
CFLAGS += -DCONFIG_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
@@ -1514,7 +1489,6 @@
OBJS += ../src/crypto/sha512-kdf.o
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1808,9 +1782,6 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
OBJS_t += ../src/radius/radius.o
-ifndef CONFIG_AP
-OBJS_t += ../src/utils/ip_addr.o
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index dcc15f1..457e32e 100644
--- a/wpa_supplicant/README-DPP
+++ b/wpa_supplicant/README-DPP
@@ -28,7 +28,6 @@
Enable DPP and protected management frame in wpa_supplicant build config
file
-CONFIG_IEEE80211W=y
CONFIG_DPP=y
hostapd build config
@@ -36,7 +35,6 @@
Enable DPP and protected management frame in hostapd build config file
-CONFIG_IEEE80211W=y
CONFIG_DPP=y
Configurator build config
@@ -120,7 +118,9 @@
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/android.config b/wpa_supplicant/android.config
index b9b5d9d..ad3af40 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -270,10 +270,6 @@
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 4e3c281..59ca153 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -381,7 +381,9 @@
else
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->psk_set) {
+ if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) && ssid->passphrase) {
+ bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+ } else if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
@@ -407,6 +409,34 @@
wep->idx = ssid->wep_tx_keyidx;
wep->keys_set = 1;
}
+#ifdef CONFIG_SAE
+ if (ssid->sae_password) {
+ struct sae_password_entry *pw;
+
+ pw = os_zalloc(sizeof(*pw));
+ if (!pw)
+ return -1;
+ os_memset(pw->peer_addr, 0xff, ETH_ALEN);
+ pw->password = os_strdup(ssid->sae_password);
+ if (!pw->password) {
+ os_free(pw);
+ return -1;
+ }
+ if (ssid->sae_password_id) {
+ pw->identifier = os_strdup(ssid->sae_password_id);
+ if (!pw->identifier) {
+ str_clear_free(pw->password);
+ os_free(pw);
+ return -1;
+ }
+ }
+
+ 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) {
wpa_printf(MSG_DEBUG,
@@ -500,10 +530,8 @@
bss->wpa_group_rekey = 86400;
}
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT)
bss->ieee80211w = ssid->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
bss->ocv = ssid->ocv;
@@ -747,6 +775,20 @@
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, ¶ms.freq.edmg);
+ }
+
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -885,6 +927,8 @@
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/bss.c b/wpa_supplicant/bss.c
index 441529c..943a340 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1038,23 +1038,30 @@
#ifdef CONFIG_P2P
/**
- * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr
* @wpa_s: Pointer to wpa_supplicant data
* @dev_addr: P2P Device Address of the GO
* Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function tries to find the entry that has the most recent update. This
+ * can help in finding the correct entry in cases where the SSID of the P2P
+ * Device may have changed recently.
*/
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss, *found = NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
u8 addr[ETH_ALEN];
if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
- addr) == 0 &&
- os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
- return bss;
+ addr) != 0 ||
+ os_memcmp(addr, dev_addr, ETH_ALEN) != 0)
+ continue;
+ if (!found ||
+ os_reltime_before(&found->last_update, &bss->last_update))
+ found = bss;
}
- return NULL;
+ return found;
}
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2895dc8..d100c46 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -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"
@@ -740,12 +741,10 @@
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
@@ -910,7 +909,6 @@
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
pos == buf ? "" : " ");
@@ -930,7 +928,6 @@
}
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
@@ -1614,7 +1611,7 @@
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
char *name = os_strdup(value + 4);
- if (name == NULL)
+ if (!name)
return -1;
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) name;
@@ -1630,9 +1627,9 @@
size_t res_len;
tmp = wpa_config_parse_string(value, &res_len);
- if (tmp == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: failed to parse "
- "password.", line);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse password.", line);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
@@ -1650,13 +1647,14 @@
/* NtPasswordHash: hash:<32 hex digits> */
if (os_strlen(value + 5) != 2 * 16) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
- "(expected 32 hex digits)", line);
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid password hash length (expected 32 hex digits)",
+ line);
return -1;
}
hash = os_malloc(16);
- if (hash == NULL)
+ if (!hash)
return -1;
if (hexstr2bin(value + 5, hash, 16)) {
@@ -1683,19 +1681,118 @@
}
+static int wpa_config_parse_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ u8 *hash;
+
+ if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.machine_password)
+ return 1; /* Already unset */
+ wpa_printf(MSG_DEBUG,
+ "Unset configuration string 'machine_password'");
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = NULL;
+ ssid->eap.machine_password_len = 0;
+ return 0;
+ }
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+
+ if (!name)
+ return -1;
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) name;
+ ssid->eap.machine_password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (os_strncmp(value, "hash:", 5) != 0) {
+ char *tmp;
+ size_t res_len;
+
+ tmp = wpa_config_parse_string(value, &res_len);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse machine_password.",
+ line);
+ return -1;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+ (u8 *) tmp, res_len);
+
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) tmp;
+ ssid->eap.machine_password_len = res_len;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+ }
+
+
+ /* NtPasswordHash: hash:<32 hex digits> */
+ if (os_strlen(value + 5) != 2 * 16) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
+ line);
+ return -1;
+ }
+
+ hash = os_malloc(16);
+ if (!hash)
+ return -1;
+
+ if (hexstr2bin(value + 5, hash, 16)) {
+ os_free(hash);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
+ line);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+ if (ssid->eap.machine_password &&
+ ssid->eap.machine_password_len == 16 &&
+ os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = hash;
+ ssid->eap.machine_password_len = 16;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+}
+
+
#ifndef NO_CONFIG_WRITE
+
static char * wpa_config_write_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
char *buf;
- if (ssid->eap.password == NULL)
+ if (!ssid->eap.password)
return NULL;
#ifdef CONFIG_EXT_PASSWORD
if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
buf = os_zalloc(4 + ssid->eap.password_len + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "ext:", 4);
os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
@@ -1709,7 +1806,7 @@
}
buf = os_malloc(5 + 32 + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "hash:", 5);
@@ -1717,6 +1814,44 @@
return buf;
}
+
+
+static char * wpa_config_write_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *buf;
+
+ if (!ssid->eap.machine_password)
+ return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ return wpa_config_write_string(
+ ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ }
+
+ buf = os_malloc(5 + 32 + 1);
+ if (!buf)
+ return NULL;
+
+ os_memcpy(buf, "hash:", 5);
+ wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
+
+ return buf;
+}
+
#endif /* NO_CONFIG_WRITE */
#endif /* IEEE8021X_EAPOL */
@@ -2141,23 +2276,24 @@
/* STR: Define a string variable for an ASCII string; f = field name */
#ifdef NO_CONFIG_WRITE
#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, OFFSET(eap.m)
#else /* NO_CONFIG_WRITE */
#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, wpa_config_write_str, \
+ OFFSET(eap.m)
#endif /* NO_CONFIG_WRITE */
#define STR(f) _STR(f), NULL, NULL, NULL, 0
-#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
+#define STRe(f, m) _STRe(f, m), NULL, NULL, NULL, 0
#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
-#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
+#define STR_KEYe(f, m) _STRe(f, m), NULL, NULL, NULL, 1
/* STR_LEN: Define a string variable with a separate variable for storing the
* data length. Unlike STR(), this can be used to store arbitrary binary data
* (i.e., even nul termination character). */
#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
-#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
+#define _STR_LENe(f, m) _STRe(f, m), OFFSET(eap.m ## _len)
#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
-#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
+#define STR_LENe(f, m) _STR_LENe(f, m), NULL, NULL, 0
#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
@@ -2168,17 +2304,17 @@
#ifdef NO_CONFIG_WRITE
#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, OFFSET(eap.m), (void *) 0
#else /* NO_CONFIG_WRITE */
#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
- OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, wpa_config_write_int, \
+ OFFSET(eap.m), (void *) 0
#endif /* NO_CONFIG_WRITE */
/* INT: Define an integer variable */
#define INT(f) _INT(f), NULL, NULL, 0
-#define INTe(f) _INTe(f), NULL, NULL, 0
+#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
/* INT_RANGE: Define an integer variable with allowed value range */
#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
@@ -2246,51 +2382,74 @@
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
- { STR_LENe(identity) },
- { STR_LENe(anonymous_identity) },
- { STR_LENe(imsi_identity) },
+ { STR_LENe(identity, identity) },
+ { STR_LENe(anonymous_identity, anonymous_identity) },
+ { STR_LENe(imsi_identity, imsi_identity) },
+ { STR_LENe(machine_identity, machine_identity) },
{ FUNC_KEY(password) },
- { STRe(ca_cert) },
- { STRe(ca_path) },
- { STRe(client_cert) },
- { STRe(private_key) },
- { STR_KEYe(private_key_passwd) },
- { STRe(dh_file) },
- { STRe(subject_match) },
- { STRe(check_cert_subject) },
- { STRe(altsubject_match) },
- { STRe(domain_suffix_match) },
- { STRe(domain_match) },
- { STRe(ca_cert2) },
- { STRe(ca_path2) },
- { STRe(client_cert2) },
- { STRe(private_key2) },
- { STR_KEYe(private_key2_passwd) },
- { STRe(dh_file2) },
- { STRe(subject_match2) },
- { STRe(check_cert_subject2) },
- { STRe(altsubject_match2) },
- { STRe(domain_suffix_match2) },
- { STRe(domain_match2) },
- { STRe(phase1) },
- { STRe(phase2) },
- { STRe(pcsc) },
- { STR_KEYe(pin) },
- { STRe(engine_id) },
- { STRe(key_id) },
- { STRe(cert_id) },
- { STRe(ca_cert_id) },
- { STR_KEYe(pin2) },
- { STRe(engine2_id) },
- { STRe(key2_id) },
- { STRe(cert2_id) },
- { STRe(ca_cert2_id) },
- { INTe(engine) },
- { INTe(engine2) },
+ { FUNC_KEY(machine_password) },
+ { STRe(ca_cert, cert.ca_cert) },
+ { STRe(ca_path, cert.ca_path) },
+ { STRe(client_cert, cert.client_cert) },
+ { STRe(private_key, cert.private_key) },
+ { STR_KEYe(private_key_passwd, cert.private_key_passwd) },
+ { STRe(dh_file, cert.dh_file) },
+ { STRe(subject_match, cert.subject_match) },
+ { STRe(check_cert_subject, cert.check_cert_subject) },
+ { STRe(altsubject_match, cert.altsubject_match) },
+ { STRe(domain_suffix_match, cert.domain_suffix_match) },
+ { STRe(domain_match, cert.domain_match) },
+ { STRe(ca_cert2, phase2_cert.ca_cert) },
+ { STRe(ca_path2, phase2_cert.ca_path) },
+ { STRe(client_cert2, phase2_cert.client_cert) },
+ { STRe(private_key2, phase2_cert.private_key) },
+ { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
+ { STRe(dh_file2, phase2_cert.dh_file) },
+ { STRe(subject_match2, phase2_cert.subject_match) },
+ { STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
+ { STRe(altsubject_match2, phase2_cert.altsubject_match) },
+ { STRe(domain_suffix_match2, phase2_cert.domain_suffix_match) },
+ { STRe(domain_match2, phase2_cert.domain_match) },
+ { STRe(phase1, phase1) },
+ { STRe(phase2, phase2) },
+ { STRe(machine_phase2, machine_phase2) },
+ { STRe(pcsc, pcsc) },
+ { STR_KEYe(pin, cert.pin) },
+ { STRe(engine_id, cert.engine_id) },
+ { STRe(key_id, cert.key_id) },
+ { STRe(cert_id, cert.cert_id) },
+ { STRe(ca_cert_id, cert.ca_cert_id) },
+ { STR_KEYe(pin2, phase2_cert.pin) },
+ { STRe(engine_id2, phase2_cert.engine_id) },
+ { STRe(key_id2, phase2_cert.key_id) },
+ { STRe(cert_id2, phase2_cert.cert_id) },
+ { STRe(ca_cert_id2, phase2_cert.ca_cert_id) },
+ { INTe(engine, cert.engine) },
+ { INTe(engine2, phase2_cert.engine) },
+ { STRe(machine_ca_cert, machine_cert.ca_cert) },
+ { STRe(machine_ca_path, machine_cert.ca_path) },
+ { STRe(machine_client_cert, machine_cert.client_cert) },
+ { STRe(machine_private_key, machine_cert.private_key) },
+ { STR_KEYe(machine_private_key_passwd,
+ machine_cert.private_key_passwd) },
+ { STRe(machine_dh_file, machine_cert.dh_file) },
+ { STRe(machine_subject_match, machine_cert.subject_match) },
+ { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
+ { STRe(machine_altsubject_match, machine_cert.altsubject_match) },
+ { STRe(machine_domain_suffix_match,
+ machine_cert.domain_suffix_match) },
+ { STRe(machine_domain_match, machine_cert.domain_match) },
+ { STR_KEYe(machine_pin, machine_cert.pin) },
+ { STRe(machine_engine_id, machine_cert.engine_id) },
+ { STRe(machine_key_id, machine_cert.key_id) },
+ { STRe(machine_cert_id, machine_cert.cert_id) },
+ { STRe(machine_ca_cert_id, machine_cert.ca_cert_id) },
+ { INTe(machine_engine, machine_cert.engine) },
+ { INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
- { INTe(sim_num) },
- { STRe(openssl_ciphers) },
- { INTe(erp) },
+ { INTe(sim_num, sim_num) },
+ { STRe(openssl_ciphers, openssl_ciphers) },
+ { INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
@@ -2300,9 +2459,10 @@
{ INT(priority) },
#ifdef IEEE8021X_EAPOL
{ INT(eap_workaround) },
- { STRe(pac_file) },
- { INTe(fragment_size) },
- { INTe(ocsp) },
+ { STRe(pac_file, pac_file) },
+ { INTe(fragment_size, fragment_size) },
+ { INTe(ocsp, cert.ocsp) },
+ { INTe(ocsp2, phase2_cert.ocsp) },
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
{ INT_RANGE(mode, 0, 5) },
@@ -2314,16 +2474,16 @@
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
-#ifdef CONFIG_IEEE80211W
{ INT_RANGE(ieee80211w, 0, 2) },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
{ FUNC(ocv) },
#endif /* CONFIG_OCV */
{ FUNC(peerkey) /* obsolete - removed */ },
{ INT_RANGE(mixed_cell, 0, 1) },
- { INT_RANGE(frequency, 0, 65000) },
+ { 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 */
@@ -2514,48 +2674,44 @@
#ifdef IEEE8021X_EAPOL
+
+static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert)
+{
+ os_free(cert->ca_cert);
+ os_free(cert->ca_path);
+ os_free(cert->client_cert);
+ os_free(cert->private_key);
+ str_clear_free(cert->private_key_passwd);
+ os_free(cert->dh_file);
+ os_free(cert->subject_match);
+ os_free(cert->check_cert_subject);
+ os_free(cert->altsubject_match);
+ os_free(cert->domain_suffix_match);
+ os_free(cert->domain_match);
+ str_clear_free(cert->pin);
+ os_free(cert->engine_id);
+ os_free(cert->key_id);
+ os_free(cert->cert_id);
+ os_free(cert->ca_cert_id);
+}
+
+
static void eap_peer_config_free(struct eap_peer_config *eap)
{
os_free(eap->eap_methods);
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
- os_free(eap->ca_cert);
- os_free(eap->ca_path);
- os_free(eap->client_cert);
- os_free(eap->private_key);
- str_clear_free(eap->private_key_passwd);
- os_free(eap->dh_file);
- os_free(eap->subject_match);
- os_free(eap->check_cert_subject);
- os_free(eap->altsubject_match);
- os_free(eap->domain_suffix_match);
- os_free(eap->domain_match);
- os_free(eap->ca_cert2);
- os_free(eap->ca_path2);
- os_free(eap->client_cert2);
- os_free(eap->private_key2);
- str_clear_free(eap->private_key2_passwd);
- os_free(eap->dh_file2);
- os_free(eap->subject_match2);
- os_free(eap->check_cert_subject2);
- os_free(eap->altsubject_match2);
- os_free(eap->domain_suffix_match2);
- os_free(eap->domain_match2);
+ bin_clear_free(eap->machine_password, eap->machine_password_len);
+ eap_peer_config_free_cert(&eap->cert);
+ eap_peer_config_free_cert(&eap->phase2_cert);
+ eap_peer_config_free_cert(&eap->machine_cert);
os_free(eap->phase1);
os_free(eap->phase2);
+ os_free(eap->machine_phase2);
os_free(eap->pcsc);
- str_clear_free(eap->pin);
- os_free(eap->engine_id);
- os_free(eap->key_id);
- os_free(eap->cert_id);
- os_free(eap->ca_cert_id);
- os_free(eap->key2_id);
- os_free(eap->cert2_id);
- os_free(eap->ca_cert2_id);
- str_clear_free(eap->pin2);
- os_free(eap->engine2_id);
os_free(eap->otp);
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
@@ -2563,6 +2719,7 @@
str_clear_free(eap->external_sim_resp);
os_free(eap->openssl_ciphers);
}
+
#endif /* IEEE8021X_EAPOL */
@@ -2609,6 +2766,9 @@
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));
}
@@ -2727,6 +2887,8 @@
#ifdef CONFIG_MBO
os_free(config->non_pref_chan);
#endif /* CONFIG_MBO */
+ os_free(config->dpp_name);
+ os_free(config->dpp_mud_url);
os_free(config);
}
@@ -2901,9 +3063,7 @@
ssid->vht_tx_mcs_nss_8 = -1;
#endif /* CONFIG_VHT_OVERRIDES */
ssid->proactive_key_caching = -1;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MACSEC
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
@@ -2948,6 +3108,15 @@
}
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) {
@@ -4827,6 +4996,8 @@
{ 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 },
{ FUNC(ap_vendor_elements), 0 },
@@ -4866,7 +5037,11 @@
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
+#ifdef CONFIG_DPP
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
+ { STR(dpp_name), 0 },
+ { STR(dpp_mud_url), 0 },
+#endif /* CONFIG_DPP */
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
#ifdef CONFIG_WNM
@@ -4987,6 +5162,7 @@
"AC item", line);
return -1;
}
+ return ret;
}
#endif /* CONFIG_AP */
if (line < 0)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 46ab9ca..922a75e 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1165,6 +1165,19 @@
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;
+
+ /**
* dtim_period - Default DTIM period in Beacon intervals
*
* This parameter can be used to set the default value for network
@@ -1492,6 +1505,16 @@
int dpp_config_processing;
/**
+ * dpp_name - Name for Enrollee's DPP Configuration Request
+ */
+ char *dpp_name;
+
+ /**
+ * dpp_mud_url - MUD URL for Enrollee's DPP Configuration Request
+ */
+ char *dpp_mud_url;
+
+ /**
* coloc_intf_reporting - Colocated interference reporting
*
* dot11CoLocIntfReportingActivated
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 6fc18ba..7651465 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -745,9 +745,9 @@
#define STR(t) write_str(f, #t, ssid)
#define INT(t) write_int(f, #t, ssid->t, 0)
-#define INTe(t) write_int(f, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(f, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(f, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
@@ -774,7 +774,9 @@
STR(identity);
STR(anonymous_identity);
STR(imsi_identity);
+ STR(machine_identity);
STR(password);
+ STR(machine_password);
STR(ca_cert);
STR(ca_path);
STR(client_cert);
@@ -797,8 +799,20 @@
STR(altsubject_match2);
STR(domain_suffix_match2);
STR(domain_match2);
+ STR(machine_ca_cert);
+ STR(machine_ca_path);
+ STR(machine_client_cert);
+ STR(machine_private_key);
+ STR(machine_private_key_passwd);
+ STR(machine_dh_file);
+ STR(machine_subject_match);
+ STR(machine_check_cert_subject);
+ STR(machine_altsubject_match);
+ STR(machine_domain_suffix_match);
+ STR(machine_domain_match);
STR(phase1);
STR(phase2);
+ STR(machine_phase2);
STR(pcsc);
STR(pin);
STR(engine_id);
@@ -810,11 +824,12 @@
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
+ INTe(machine_engine, machine_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
STR(openssl_ciphers);
- INTe(erp);
+ INTe(erp, erp);
#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
write_wep_key(f, i, ssid);
@@ -823,13 +838,17 @@
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
- INTe(ocsp);
- INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INTe(ocsp, cert.ocsp);
+ INTe(ocsp2, phase2_cert.ocsp);
+ INTe(machine_ocsp, machine_cert.ocsp);
+ INT_DEFe(sim_num, sim_num, DEFAULT_USER_SELECTED_SIM);
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
INT(frequency);
+ INT(enable_edmg);
+ INT(edmg_channel);
INT(fixed_freq);
#ifdef CONFIG_ACS
INT(acs);
@@ -846,10 +865,8 @@
INT(pbss);
INT(wps_disabled);
INT(fils_dh_group);
-#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
write_go_p2p_dev_addr(f, ssid);
@@ -1390,6 +1407,13 @@
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);
+
if (config->ap_vendor_elements) {
int i, len = wpabuf_len(config->ap_vendor_elements);
const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 6fd3a01..af8317b 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -47,30 +47,6 @@
u8 p2p;
};
-/**
- * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
- *
- * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
- *
- * 1 = IBSS (ad-hoc, peer-to-peer)
- *
- * 2 = AP (access point)
- *
- * 3 = P2P Group Owner (can be set in the configuration file)
- *
- * 4 = P2P Group Formation (used internally; not in configuration
- * files)
- *
- * 5 = Mesh
- *
- * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
- * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
- * (fixed group key TKIP/CCMP) is available for backwards compatibility,
- * but its use is deprecated. WPA-None requires following network block
- * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or
- * CCMP, but not both), and psk must also be set (either directly or
- * using ASCII passphrase).
- */
enum wpas_mode {
WPAS_MODE_INFRA = 0,
WPAS_MODE_IBSS = 1,
@@ -236,6 +212,8 @@
*/
char *sae_password_id;
+ struct sae_pt *pt;
+
/**
* ext_psk - PSK/passphrase name in external storage
*
@@ -469,7 +447,6 @@
*/
char *id_str;
-#ifdef CONFIG_IEEE80211W
/**
* ieee80211w - Whether management frame protection is enabled
*
@@ -483,7 +460,6 @@
* followed).
*/
enum mfp_options ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
/**
@@ -509,6 +485,23 @@
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/config_winreg.c b/wpa_supplicant/config_winreg.c
index 3ea5c80..0f2a30a 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: Windows registry
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -868,9 +868,9 @@
#define STR(t) write_str(netw, #t, ssid)
#define INT(t) write_int(netw, #t, ssid->t, 0)
-#define INTe(t) write_int(netw, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(netw, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(netw, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
@@ -920,8 +920,8 @@
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
@@ -931,16 +931,14 @@
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
-1);
INT(disabled);
-#ifdef CONFIG_IEEE80211W
write_int(netw, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_HS20
INT(update_identifier);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8efc08d..7f8ec4a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -11,7 +11,6 @@
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
-#include <net/ethernet.h>
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
@@ -58,6 +57,12 @@
#include "dpp_supplicant.h"
#include "sme.h"
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#elif !defined(__CYGWIN__) && !defined(CONFIG_NATIVE_WINDOWS)
+#include <net/ethernet.h>
+#endif
+
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
@@ -2654,7 +2659,6 @@
pos += ret;
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
pos == start ? "" : "+");
@@ -2669,7 +2673,6 @@
return pos;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SUITEB
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
@@ -2873,6 +2876,15 @@
}
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;
@@ -5241,10 +5253,8 @@
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
0);
@@ -10624,12 +10634,10 @@
} else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
if (wpas_ctrl_resend_assoc(wpa_s) < 0)
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
sme_event_unprot_disconnect(
wpa_s, wpa_s->bssid, NULL,
WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
-#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
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 @@
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 @@
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 6c36d91..2582092 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -984,8 +984,7 @@
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;
@@ -1012,9 +1011,7 @@
#ifdef CONFIG_INTERWORKING
capabilities[num_items++] = "interworking";
#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_IEEE80211W
capabilities[num_items++] = "pmf";
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MESH
capabilities[num_items++] = "mesh";
#endif /* CONFIG_MESH */
@@ -1030,6 +1027,9 @@
#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,
@@ -2753,11 +2753,9 @@
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-eap-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
@@ -2771,11 +2769,9 @@
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-psk-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
@@ -3990,6 +3986,173 @@
/**
+ * 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
@@ -4497,7 +4660,7 @@
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,
@@ -4550,6 +4713,10 @@
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";
@@ -4608,11 +4775,9 @@
/* Management group (RSN only) */
if (ie_data->proto == WPA_PROTO_RSN) {
switch (ie_data->mgmt_group_cipher) {
-#ifdef CONFIG_IEEE80211W
case WPA_CIPHER_AES_128_CMAC:
group = "aes128cmac";
break;
-#endif /* CONFIG_IEEE80211W */
default:
group = "";
break;
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_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 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_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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
"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 @@
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 @@
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 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 @@
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 @@
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 @@
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/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index d80e2d4..d9009ba 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -742,7 +742,7 @@
DBusConnection *con = eloop_ctx;
struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
- wpa_printf(MSG_DEBUG,
+ wpa_printf(MSG_MSGDUMP,
"dbus: %s: Timeout - sending changed properties of object %s",
__func__, obj_desc->path);
wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index cdfb197..792ab24 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -310,10 +310,6 @@
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -366,7 +362,7 @@
#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
@@ -610,6 +606,4 @@
#CONFIG_OWE=y
# Device Provisioning Protocol (DPP)
-# This requires CONFIG_IEEE80211W=y to be enabled, too. (see
-# wpa_supplicant/README-DPP for details)
CONFIG_DPP=y
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 30ef5db..ff30e9a 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -149,6 +149,8 @@
static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->suitable_network = 0;
+ wpa_s->no_suitable_network = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
@@ -158,6 +160,141 @@
}
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error result;
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connection timeout - report Connection Status Result");
+ if (wpa_s->suitable_network)
+ result = DPP_STATUS_AUTH_FAILURE;
+ else if (wpa_s->no_suitable_network)
+ result = DPP_STATUS_NO_AP;
+ else
+ result = 255; /* What to report here for unexpected state? */
+ wpas_dpp_send_conn_status_result(wpa_s, result);
+}
+
+
+static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
+{
+ char *str, *end, *pos;
+ size_t len;
+ unsigned int i;
+ u8 last_op_class = 0;
+ int res;
+
+ if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
+ return NULL;
+
+ len = wpa_s->num_last_scan_freqs * 8;
+ str = os_zalloc(len);
+ if (!str)
+ return NULL;
+ end = str + len;
+ pos = str;
+
+ for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+
+ mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
+ 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES)
+ continue;
+ if (op_class == last_op_class)
+ res = os_snprintf(pos, end - pos, ",%d", channel);
+ else
+ res = os_snprintf(pos, end - pos, "%s%d/%d",
+ pos == str ? "" : ",",
+ op_class, channel);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ last_op_class = op_class;
+ }
+
+ if (pos == str) {
+ os_free(str);
+ str = NULL;
+ }
+ return str;
+}
+
+
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result)
+{
+ struct wpabuf *msg;
+ const char *channel_list = NULL;
+ char *channel_list_buf = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+ auth->conn_status_requested = 0;
+ wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
+ result);
+
+ if (result == DPP_STATUS_NO_AP) {
+ channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
+ channel_list = channel_list_buf;
+ }
+
+ msg = dpp_build_conn_status_result(auth, result,
+ ssid ? ssid->ssid :
+ wpa_s->dpp_last_ssid,
+ ssid ? ssid->ssid_len :
+ wpa_s->dpp_last_ssid_len,
+ channel_list);
+ os_free(channel_list_buf);
+ if (!msg) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_CONNECTION_STATUS_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ auth->remove_on_tx_status = 1;
+
+ return;
+}
+
+
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (auth && auth->conn_status_requested)
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -183,18 +320,30 @@
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
+ auth->connect_on_tx_status = 0;
wpa_printf(MSG_DEBUG,
"DPP: Try to connect after completed configuration result");
wpas_dpp_try_to_connect(wpa_s);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
+ if (auth->conn_status_requested) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start 15 second timeout for reporting connection status result");
+ eloop_cancel_timeout(
+ wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 15, 0, wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ } else {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
return;
}
#endif /* CONFIG_DPP2 */
if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
- "DPP: Terminate authentication exchange due to an earlier error");
+ "DPP: Terminate authentication exchange due to a request to do so on TX status");
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
@@ -812,12 +961,13 @@
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;
@@ -844,27 +994,27 @@
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) {
@@ -879,29 +1029,32 @@
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, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
+
return ssid;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -911,14 +1064,15 @@
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;
@@ -935,49 +1089,56 @@
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);
@@ -1005,7 +1166,7 @@
}
}
- return wpas_dpp_process_config(wpa_s, auth);
+ return wpas_dpp_process_config(wpa_s, auth, conf);
}
@@ -1019,6 +1180,7 @@
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;
@@ -1056,9 +1218,14 @@
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
@@ -1107,27 +1274,19 @@
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
+ int *supp_op_classes;
wpa_s->dpp_gas_client = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- wpa_s->dpp_netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- buf = dpp_build_conf_req(auth, json);
+ supp_op_classes = wpas_supp_op_classes(wpa_s);
+ buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
+ wpa_s->dpp_netrole_ap,
+ wpa_s->conf->dpp_mud_url,
+ supp_op_classes);
+ os_free(supp_op_classes);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -1281,6 +1440,24 @@
}
+static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conn_status_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -1304,6 +1481,23 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ auth->waiting_conn_status_result = 1;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(16, 0,
+ wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq :
+ auth->curr_freq);
+ return;
+ }
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (status == DPP_STATUS_OK)
@@ -1316,12 +1510,57 @@
}
+static void wpas_dpp_rx_conn_status_result(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+}
+
+
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;
- return wpas_dpp_handle_config_obj(wpa_s, auth);
+ 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 res;
}
#endif /* CONFIG_DPP2 */
@@ -1394,6 +1633,9 @@
status[0]);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" status=%u", MAC2STR(src), status[0]);
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, status[0]);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1417,6 +1659,9 @@
"DPP: Network Introduction protocol resulted in failure");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" fail=peer_connector_validation_failed", MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1859,6 +2104,9 @@
case DPP_PA_CONFIGURATION_RESULT:
wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1894,6 +2142,18 @@
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
+
+ if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
+ /* wpas_dpp_auth_success() would normally have been called from
+ * TX status handler, but since there was no such handler call
+ * yet, simply send out the event message and proceed with
+ * exchange. */
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ }
+
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
@@ -1976,7 +2236,10 @@
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);
@@ -2299,6 +2562,9 @@
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 9ba315f..b337982 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +10,8 @@
#ifndef DPP_SUPPLICANT_H
#define DPP_SUPPLICANT_H
+enum dpp_status_error;
+
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
@@ -26,5 +29,8 @@
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 471fc17..139402e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -316,8 +316,9 @@
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP || wpa_s->drv_authorized_port)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ wpa_s->drv_authorized_port = 0;
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -326,6 +327,7 @@
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
wnm_clear_coloc_intf_reporting(wpa_s);
+ wpa_s->disable_mbo_oce = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->last_tk_alg = WPA_ALG_NONE;
@@ -611,7 +613,6 @@
break;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
@@ -620,7 +621,6 @@
" skip RSN IE - no mgmt frame protection");
break;
}
-#endif /* CONFIG_IEEE80211W */
if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
NO_MGMT_FRAME_PROTECTION) {
@@ -629,17 +629,6 @@
" skip RSN IE - no mgmt frame protection enabled but AP requires it");
break;
}
-#ifdef CONFIG_MBO
- if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
- wpas_get_ssid_pmf(wpa_s, ssid) !=
- NO_MGMT_FRAME_PROTECTION) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled on MBO AP");
- break;
- }
-#endif /* CONFIG_MBO */
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -647,7 +636,6 @@
return 1;
}
-#ifdef CONFIG_IEEE80211W
if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
(!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
if (debug_print)
@@ -655,7 +643,6 @@
" skip - MFP Required but network not MFP Capable");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
@@ -863,6 +850,19 @@
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;
@@ -1262,6 +1262,19 @@
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 |
@@ -1937,6 +1950,21 @@
radio_work_done(work);
}
+ os_free(wpa_s->last_scan_freqs);
+ wpa_s->last_scan_freqs = NULL;
+ wpa_s->num_last_scan_freqs = 0;
+ if (own_request && data &&
+ data->scan_info.freqs && data->scan_info.num_freqs) {
+ wpa_s->last_scan_freqs = os_malloc(sizeof(int) *
+ data->scan_info.num_freqs);
+ if (wpa_s->last_scan_freqs) {
+ os_memcpy(wpa_s->last_scan_freqs,
+ data->scan_info.freqs,
+ sizeof(int) * data->scan_info.num_freqs);
+ wpa_s->num_last_scan_freqs = data->scan_info.num_freqs;
+ }
+ }
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done:
@@ -1990,6 +2018,8 @@
return 0;
}
+ wpa_s->suitable_network++;
+
if (ssid != wpa_s->current_ssid &&
wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_s->own_disconnect_req = 1;
@@ -2010,6 +2040,7 @@
*/
return 1;
} else {
+ wpa_s->no_suitable_network++;
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -2380,7 +2411,7 @@
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];
@@ -2452,22 +2483,29 @@
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
@@ -2629,14 +2667,19 @@
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;
@@ -2656,7 +2699,7 @@
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;
@@ -2667,11 +2710,14 @@
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;
@@ -2723,6 +2769,9 @@
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) {
@@ -2831,7 +2880,7 @@
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
- already_authorized)
+ already_authorized || wpa_s->drv_authorized_port)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
/* 802.1X::portControl = Auto */
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2946,15 +2995,21 @@
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 */
}
@@ -2999,7 +3054,8 @@
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 */
/*
@@ -3062,6 +3118,10 @@
if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
return; /* P2P group removed */
wpas_auth_failed(wpa_s, "WRONG_KEY");
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s,
+ DPP_STATUS_AUTH_FAILURE);
+#endif /* CONFIG_DPP2 */
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
@@ -3510,26 +3570,22 @@
static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
struct unprot_deauth *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
struct unprot_disassoc *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
@@ -3787,14 +3843,12 @@
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
#ifdef CONFIG_SME
if (category == WLAN_ACTION_SA_QUERY) {
sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
return;
}
#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
@@ -3935,6 +3989,7 @@
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ wpa_s->drv_authorized_port = 1;
}
}
@@ -4508,9 +4563,7 @@
}
#endif /* CONFIG_AP */
-#ifdef CONFIG_IEEE80211W
sme_event_ch_switch(wpa_s);
-#endif /* CONFIG_IEEE80211W */
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
@@ -4717,6 +4770,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_supplicant_update_mac_addr(wpa_s);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
if (wpa_s->p2p_mgmt) {
wpa_supplicant_set_state(wpa_s,
WPA_DISCONNECTED);
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.cpp b/wpa_supplicant/hidl/1.3/sta_iface.cpp
index 249eebc..e82305d 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_iface.cpp
@@ -20,8 +20,8 @@
#include "interworking.h"
#include "hs20_supplicant.h"
#include "wps_supplicant.h"
-#include "dpp_supplicant.h"
#include "dpp.h"
+#include "dpp_supplicant.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
}
diff --git a/wpa_supplicant/hidl/1.3/sta_network.cpp b/wpa_supplicant/hidl/1.3/sta_network.cpp
index 273687d..242d7d7 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_network.cpp
@@ -1199,7 +1199,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_cert), "eap ca_cert")) {
+ path.c_str(), &(wpa_ssid->eap.cert.ca_cert), "eap ca_cert")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1209,7 +1209,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_path), "eap ca_path")) {
+ path.c_str(), &(wpa_ssid->eap.cert.ca_path), "eap ca_path")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1219,7 +1219,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.client_cert),
+ path.c_str(), &(wpa_ssid->eap.cert.client_cert),
"eap client_cert")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1230,7 +1230,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.key_id), "eap key_id")) {
+ id.c_str(), &(wpa_ssid->eap.cert.key_id), "eap key_id")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1241,7 +1241,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.subject_match),
+ match.c_str(), &(wpa_ssid->eap.cert.subject_match),
"eap subject_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1253,7 +1253,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.altsubject_match),
+ match.c_str(), &(wpa_ssid->eap.cert.altsubject_match),
"eap altsubject_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1263,7 +1263,7 @@
SupplicantStatus StaNetwork::setEapEngineInternal(bool enable)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->eap.engine = enable ? 1 : 0;
+ wpa_ssid->eap.cert.engine = enable ? 1 : 0;
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1271,7 +1271,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.engine_id), "eap engine_id")) {
+ id.c_str(), &(wpa_ssid->eap.cert.engine_id), "eap engine_id")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1282,7 +1282,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.domain_suffix_match),
+ match.c_str(), &(wpa_ssid->eap.cert.domain_suffix_match),
"eap domain_suffix_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1463,7 +1463,7 @@
// the first EAP method for each network.
const std::string eap_method_str = eap_get_name(
wpa_ssid->eap.eap_methods[0].vendor,
- static_cast<EapType>(wpa_ssid->eap.eap_methods[0].method));
+ static_cast<enum eap_type>(wpa_ssid->eap.eap_methods[0].method));
size_t eap_method_idx =
std::find(
std::begin(kEapMethodStrings), std::end(kEapMethodStrings),
@@ -1557,89 +1557,89 @@
std::pair<SupplicantStatus, std::string> StaNetwork::getEapCACertInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_cert) {
+ if (!wpa_ssid->eap.cert.ca_cert) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_cert)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.ca_cert)};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapCAPathInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_path) {
+ if (!wpa_ssid->eap.cert.ca_path) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_path)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.ca_path)};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapClientCertInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.client_cert) {
+ if (!wpa_ssid->eap.cert.client_cert) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.client_cert)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.client_cert)};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapPrivateKeyIdInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.key_id) {
+ if (!wpa_ssid->eap.cert.key_id) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.key_id};
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.cert.key_id};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapSubjectMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.subject_match) {
+ if (!wpa_ssid->eap.cert.subject_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.subject_match)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.subject_match)};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapAltSubjectMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.altsubject_match) {
+ if (!wpa_ssid->eap.cert.altsubject_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.altsubject_match)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.altsubject_match)};
}
std::pair<SupplicantStatus, bool> StaNetwork::getEapEngineInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.engine == 1};
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.cert.engine == 1};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapEngineIDInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.engine_id) {
+ if (!wpa_ssid->eap.cert.engine_id) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
- return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.engine_id}};
+ return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.cert.engine_id}};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapDomainSuffixMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.domain_suffix_match) {
+ if (!wpa_ssid->eap.cert.domain_suffix_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- {wpa_ssid->eap.domain_suffix_match}};
+ {wpa_ssid->eap.cert.domain_suffix_match}};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
@@ -1977,9 +1977,9 @@
if (ocspType < OcspType::NONE || ocspType > OcspType::REQUIRE_ALL_CERTS_STATUS) {
return{ SupplicantStatusCode::FAILURE_ARGS_INVALID, "" };
}
- wpa_ssid->eap.ocsp = (int) ocspType;
+ wpa_ssid->eap.cert.ocsp = (int) ocspType;
wpa_printf(
- MSG_MSGDUMP, "ocsp: %d", wpa_ssid->eap.ocsp);
+ MSG_MSGDUMP, "ocsp: %d", wpa_ssid->eap.cert.ocsp);
resetInternalStateAfterParamsUpdate();
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1988,7 +1988,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
return {{SupplicantStatusCode::SUCCESS, ""},
- (OcspType) wpa_ssid->eap.ocsp};
+ (OcspType) wpa_ssid->eap.cert.ocsp};
}
SupplicantStatus StaNetwork::setPmkCacheInternal(const std::vector<uint8_t>& serializedEntry) {
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 @@
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 @@
"\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 dabde82..585b7f0 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1395,7 +1395,11 @@
!roaming_consortium_match(ie, anqp,
cred->roaming_consortium,
cred->roaming_consortium_len)) &&
- !cred_roaming_consortiums_match(ie, anqp, cred))
+ !cred_roaming_consortiums_match(ie, anqp, cred) &&
+ (cred->required_roaming_consortium_len == 0 ||
+ !roaming_consortium_match(
+ ie, anqp, cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len)))
continue;
if (cred_no_required_oi_match(cred, bss))
@@ -1550,7 +1554,7 @@
cred->domain_suffix_match) < 0)
return -1;
- ssid->eap.ocsp = cred->ocsp;
+ ssid->eap.cert.ocsp = cred->ocsp;
return 0;
}
@@ -2258,7 +2262,7 @@
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/mbo.c b/wpa_supplicant/mbo.c
index 43b1fa7..3df86ef 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "rsn_supp/wpa.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -82,6 +83,35 @@
}
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid)
+{
+ const u8 *rsne, *mbo, *oce;
+ struct wpa_ie_data ie;
+
+ wpa_s->disable_mbo_oce = 0;
+ if (!bss)
+ return;
+ mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
+ oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
+ if (!mbo && !oce)
+ return;
+ if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
+ return; /* STA-CFON is not required to enable PMF */
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
+ return; /* AP is not using RSN */
+
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
+ wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
+ wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
+ if (wpa_s->disable_mbo_oce)
+ wpa_printf(MSG_INFO,
+ "MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
+}
+
+
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
struct wpabuf *mbo,
u8 start, u8 end)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 7354c1b..5c1a47d 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -86,7 +86,6 @@
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
-#ifdef CONFIG_IEEE80211W
conf->ieee80211w = ssid->ieee80211w;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
@@ -94,7 +93,6 @@
else
conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf->ocv = ssid->ocv;
#endif /* CONFIG_OCV */
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 4b8d6c4..e730b63 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -165,11 +165,9 @@
conf.wpa_group_rekey = -1;
conf.wpa_group_update_count = 4;
conf.wpa_pairwise_update_count = 4;
-#ifdef CONFIG_IEEE80211W
conf.ieee80211w = ieee80211w;
if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf.ocv = ocv;
#endif /* CONFIG_OCV */
@@ -186,7 +184,6 @@
return -1;
rsn->mgtk_key_id = 1;
-#ifdef CONFIG_IEEE80211W
if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
@@ -201,7 +198,6 @@
rsn->igtk_key_id, 1,
seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
@@ -545,10 +541,8 @@
len = sizeof(*ampe);
if (cat[1] == PLINK_OPEN)
len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
-#ifdef CONFIG_IEEE80211W
if (cat[1] == PLINK_OPEN && rsn->igtk_len)
len += 2 + 6 + rsn->igtk_len;
-#endif /* CONFIG_IEEE80211W */
if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
@@ -591,7 +585,6 @@
WPA_PUT_LE32(pos, 0xffffffff);
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -603,7 +596,6 @@
pos += 6;
os_memcpy(pos, rsn->igtk, rsn->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
skip_keys:
wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
@@ -774,7 +766,6 @@
WPA_GET_LE32(pos));
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -794,7 +785,6 @@
wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
sta->igtk, sta->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
free:
os_free(crypt);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index ebefd48..2ebe034 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -865,10 +865,11 @@
int i;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
- "depth=%d subject='%s'%s%s%s",
+ "depth=%d subject='%s'%s%s%s%s",
cert->depth, cert->subject, cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "",
- cert->tod ? " tod=1" : "");
+ cert->tod == 2 ? " tod=2" : "",
+ cert->tod == 1 ? " tod=1" : "");
if (cert->cert) {
char *cert_hex;
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index 6a85af4..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 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 @@
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 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 @@
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 @@
}
-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)
@@ -225,7 +234,7 @@
/* If we are configured to disable certain things, take that into
* account here. */
- if (ssid->freq_list && ssid->freq_list[0]) {
+ if (ssid && ssid->freq_list && ssid->freq_list[0]) {
for (z = 0; ; z++) {
int f = ssid->freq_list[z];
@@ -248,7 +257,7 @@
return 0;
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht) {
+ if (ssid && ssid->disable_ht) {
switch (op_class->op_class) {
case 83:
case 84:
@@ -272,7 +281,7 @@
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
- if (ssid->disable_vht) {
+ if (ssid && ssid->disable_vht) {
if (op_class->op_class >= 128 && op_class->op_class <= 130) {
/* Disable >= 80 MHz channels if VHT is disabled */
return 0;
@@ -284,7 +293,8 @@
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 @@
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 @@
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;
}
@@ -385,3 +406,24 @@
wpabuf_free(buf);
return res;
}
+
+
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s)
+{
+ int op;
+ unsigned int pos, max_num = 0;
+ int *classes;
+
+ for (op = 0; global_op_class[op].op_class; op++)
+ max_num++;
+ classes = os_zalloc((max_num + 1) * sizeof(int));
+ if (!classes)
+ return NULL;
+
+ for (op = 0, pos = 0; global_op_class[op].op_class; op++) {
+ if (wpas_op_class_supported(wpa_s, NULL, &global_op_class[op]))
+ classes[pos++] = global_op_class[op].op_class;
+ }
+
+ return classes;
+}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 23bbc21..fb509a1 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2268,6 +2268,8 @@
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
+ if (wpa_s->p2p_go_he)
+ res->he = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 8468b2f..b78ff10 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -101,10 +101,16 @@
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
/* Workaround different, undefined for Windows, error codes used here */
+#ifndef ENOTCONN
#define ENOTCONN -1
+#endif
+#ifndef EOPNOTSUPP
#define EOPNOTSUPP -1
+#endif
+#ifndef ECANCELED
#define ECANCELED -1
#endif
+#endif
/* Measurement Request element + Location Subject + Maximum Age subelement */
#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
@@ -522,7 +528,8 @@
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 @@
#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 @@
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 @@
#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(¶ms, wpa_s->mac_addr_scan);
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
struct wpa_bss *bss;
@@ -1286,6 +1312,7 @@
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 @@
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(¶ms,
+ 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 @@
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 @@
}
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(¶ms, wpa_s->mac_addr_pno);
wpa_scan_set_relative_rssi_params(wpa_s, ¶ms);
ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms);
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_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 @@
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 dd50201..cfb5bb3 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -37,9 +37,7 @@
static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
@@ -86,11 +84,16 @@
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) {
@@ -119,6 +122,7 @@
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) {
@@ -126,7 +130,31 @@
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) {
@@ -145,10 +173,13 @@
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;
}
@@ -492,7 +523,6 @@
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -505,7 +535,6 @@
wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
}
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
@@ -562,6 +591,14 @@
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;
@@ -623,7 +660,7 @@
#ifdef CONFIG_MBO
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
@@ -655,7 +692,7 @@
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) {
@@ -855,6 +892,8 @@
/* 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);
}
@@ -909,7 +948,8 @@
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;
@@ -924,7 +964,7 @@
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);
@@ -937,8 +977,9 @@
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;
@@ -953,7 +994,9 @@
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);
@@ -972,6 +1015,8 @@
params.ssid = wpa_s->sme.ext_auth_ssid;
params.ssid_len = wpa_s->sme.ext_auth_ssid_len;
params.bssid = wpa_s->sme.ext_auth_bssid;
+ if (wpa_s->conf->sae_pmkid_in_assoc && status == WLAN_STATUS_SUCCESS)
+ params.pmkid = wpa_s->sme.sae.pmkid;
wpa_drv_send_external_auth_status(wpa_s, ¶ms);
}
@@ -1020,7 +1065,8 @@
}
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);
@@ -1057,6 +1103,52 @@
}
+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)
@@ -1111,6 +1203,8 @@
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 */
@@ -1135,7 +1229,8 @@
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) {
@@ -1147,12 +1242,16 @@
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");
@@ -1161,6 +1260,12 @@
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");
@@ -1176,6 +1281,8 @@
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;
@@ -1197,6 +1304,37 @@
}
+static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ wpa_printf(MSG_DEBUG,
+ "SME: SAE completed - setting PMK for 4-way handshake");
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_s->sme.sae.pmkid, bssid);
+ if (wpa_s->conf->sae_pmkid_in_assoc) {
+ /* Update the own RSNE contents now that we have set the PMK
+ * and added a PMKSA cache entry based on the successfully
+ * completed SAE exchange. In practice, this will add the PMKID
+ * into RSNE. */
+ if (wpa_s->sme.assoc_req_ie_len + 2 + PMKID_LEN >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Not enough room for inserting own PMKID into RSNE");
+ return -1;
+ }
+ if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ wpa_s->sme.sae.pmkid) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Updated Association Request IEs",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ }
+
+ return 0;
+}
+
+
void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
const u8 *auth_frame, size_t len)
{
@@ -1230,10 +1368,8 @@
if (res != 1)
return;
- wpa_printf(MSG_DEBUG,
- "SME: SAE completed - setting PMK for 4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0)
+ return;
}
}
@@ -1286,10 +1422,8 @@
if (res != 1)
return;
- wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
- "4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->pending_bssid) < 0)
+ return;
}
#endif /* CONFIG_SAE */
@@ -1778,6 +1912,11 @@
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;
@@ -1995,15 +2134,17 @@
if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
sme_update_ft_ies(wpa_s, NULL, NULL, 0);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
sme_stop_sa_query(wpa_s);
-#endif /* CONFIG_IEEE80211W */
}
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);
@@ -2292,8 +2433,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
static const unsigned int sa_query_max_timeout = 1000;
static const unsigned int sa_query_retry_timeout = 201;
static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
@@ -2582,5 +2721,3 @@
else if (data[0] == WLAN_SA_QUERY_RESPONSE)
sme_process_sa_query_response(wpa_s, sa, data, len);
}
-
-#endif /* CONFIG_IEEE80211W */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index c147649..270be9e 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -271,7 +271,6 @@
WNM_SLEEP_SUBELEM_GTK,
ptr);
ptr += 13 + gtk_len;
-#ifdef CONFIG_IEEE80211W
} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
@@ -281,7 +280,6 @@
wpa_wnmsleep_install_key(wpa_s->wpa,
WNM_SLEEP_SUBELEM_IGTK, ptr);
ptr += 10 + WPA_IGTK_LEN;
-#endif /* CONFIG_IEEE80211W */
} else
break; /* skip the loop */
}
@@ -1371,7 +1369,7 @@
const u8 *vendor;
#endif /* CONFIG_MBO */
- if (wpa_s->conf->disable_btm)
+ if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
return;
if (end - pos < 5)
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 5b2154e..47cec0b 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1427,22 +1427,18 @@
#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",
-#ifdef CONFIG_IEEE80211W
"ieee80211w",
-#endif /* CONFIG_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 */
@@ -4021,6 +4017,22 @@
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) {
wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONF_RECEIVED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_AKM)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_SSID)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONNECTOR)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_PASS)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_PSK)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_C_SIGN_KEY)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_NET_ACCESS_KEY)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -4592,8 +4604,11 @@
if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
continue;
#endif /* _DIRENT_HAVE_D_TYPE */
+ /* Skip current/previous directory and special P2P Device
+ * interfaces. */
if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
+ os_strcmp(dent->d_name, "..") == 0 ||
+ os_strncmp(dent->d_name, "p2p-dev-", 8) == 0)
continue;
printf("Selected interface '%s'\n", dent->d_name);
ifname = os_strdup(dent->d_name);
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 @@
}
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 @@
}
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 d1dd540..e14bffd 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -125,6 +125,9 @@
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
/* Configure default/group WEP keys for static WEP */
@@ -400,7 +403,10 @@
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;
@@ -422,10 +428,8 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -691,13 +695,7 @@
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- int i, max;
-
-#ifdef CONFIG_IEEE80211W
- max = 6;
-#else /* CONFIG_IEEE80211W */
- max = 4;
-#endif /* CONFIG_IEEE80211W */
+ int i, max = 6;
/* MLME-DELETEKEYS.request */
for (i = 0; i < max; i++) {
@@ -846,6 +844,9 @@
enum wpa_states state)
{
enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ Boolean update_fils_connect_params = FALSE;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -943,8 +944,12 @@
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (!fils_hlp_sent && ssid && ssid->eap.erp)
- wpas_update_fils_connect_params(wpa_s);
+ update_fils_connect_params = TRUE;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -984,7 +989,15 @@
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
}
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ if (update_fils_connect_params)
+ wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
}
@@ -1180,7 +1193,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1188,7 +1200,6 @@
"reject");
return -1;
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -1226,14 +1237,16 @@
{
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 &&
@@ -1313,7 +1326,6 @@
ie.group_cipher = ssid->group_cipher;
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
ie.mgmt_group_cipher = 0;
if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (ssid->group_mgmt_cipher &
@@ -1332,7 +1344,6 @@
ie.mgmt_group_cipher =
WPA_CIPHER_AES_128_CMAC;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OWE
if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only &&
@@ -1352,12 +1363,10 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d proto %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
ie.mgmt_group_cipher);
}
-#endif /* CONFIG_IEEE80211W */
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1368,7 +1377,9 @@
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;
}
@@ -1414,7 +1425,8 @@
if (0) {
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SHA384
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT FT/802.1X-SHA384");
@@ -1457,7 +1469,8 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
if (!ssid->ft_eap_pmksa_caching &&
@@ -1487,7 +1500,6 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1496,7 +1508,6 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1527,7 +1538,13 @@
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "RSN: Management frame protection required but the selected AP does not enable it");
+ return -1;
+ }
+
sel = ie.mgmt_group_cipher;
if (ssid->group_mgmt_cipher)
sel &= ssid->group_mgmt_cipher;
@@ -1561,16 +1578,23 @@
wpa_s->mgmt_group_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
-#endif /* CONFIG_IEEE80211W */
#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) {
@@ -1712,7 +1736,7 @@
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- if (!wpa_s->conf->disable_btm)
+ if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
*pos |= 0x08; /* Bit 19 - BSS Transition */
#endif /* CONFIG_WNM */
break;
@@ -1919,6 +1943,36 @@
}
+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);
/**
@@ -1965,6 +2019,14 @@
} 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) {
@@ -2066,6 +2128,10 @@
bss->ie_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
ssid->mode == WPAS_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
@@ -2154,6 +2220,7 @@
struct hostapd_freq_params vht_freq;
int chwidth, seg0, seg1;
u32 vht_caps = 0;
+ int is_24ghz;
freq->freq = ssid->frequency;
@@ -2205,8 +2272,8 @@
if (!mode)
return;
- /* HE can work without HT + VHT */
- freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht) {
@@ -2219,6 +2286,10 @@
if (!freq->ht_enabled)
return;
+ /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+ if (is_24ghz)
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* Setup higher BW only for 5 GHz */
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return;
@@ -2339,6 +2410,9 @@
if (!vht_freq.vht_enabled)
return;
+ /* Enable HE for VHT */
+ vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* setup center_freq1, bandwidth */
for (j = 0; j < ARRAY_SIZE(vht80); j++) {
if (freq->channel >= vht80[j] &&
@@ -2413,7 +2487,8 @@
}
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,
@@ -2816,7 +2891,7 @@
#ifdef CONFIG_MBO
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2931,6 +3006,12 @@
}
#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;
@@ -2956,6 +3037,24 @@
}
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ os_memset(¶ms, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, ¶ms, NULL);
+ if (!wpa_ie)
+ return;
+
+ wpa_drv_update_connect_params(wpa_s, ¶ms, WPA_DRV_UPDATE_ASSOC_IES);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_OWE */
+
+
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -2984,6 +3083,117 @@
#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)
{
@@ -3019,6 +3229,7 @@
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;
@@ -3111,6 +3322,8 @@
/* 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, ¶ms, NULL);
if (!wpa_ie) {
@@ -3202,6 +3415,71 @@
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,
+ ¶ms.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;
@@ -3230,7 +3508,7 @@
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
- params.req_key_mgmt_offload = 1;
+ params.req_handshake_offload = 1;
if (wpa_s->conf->key_mgmt_offload) {
if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -3252,7 +3530,6 @@
params.drop_unencrypted = use_crypt;
-#ifdef CONFIG_IEEE80211W
params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3271,7 +3548,6 @@
#endif /* CONFIG_OWE */
}
}
-#endif /* CONFIG_IEEE80211W */
params.p2p = ssid->p2p_group;
@@ -3764,9 +4040,15 @@
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) {
@@ -4345,6 +4627,11 @@
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;
}
@@ -5953,7 +6240,7 @@
hs20_init(wpa_s);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (wpa_s->conf->oce) {
+ if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
if ((wpa_s->conf->oce & OCE_STA) &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
wpa_s->enable_oce = OCE_STA;
@@ -6051,6 +6338,7 @@
}
os_free(wpa_s->ssids_from_scan_req);
+ os_free(wpa_s->last_scan_freqs);
os_free(wpa_s);
}
@@ -6920,8 +7208,8 @@
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- str_clear_free(eap->pin);
- eap->pin = os_strdup(value);
+ str_clear_free(eap->cert.pin);
+ eap->cert.pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6935,8 +7223,8 @@
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- str_clear_free(eap->private_key_passwd);
- eap->private_key_passwd = os_strdup(value);
+ str_clear_free(eap->cert.private_key_passwd);
+ eap->cert.private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -7023,7 +7311,6 @@
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
-#ifdef CONFIG_IEEE80211W
if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
!(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -7052,9 +7339,6 @@
}
return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
- return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 1159bdc..ba511b9 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -311,6 +311,26 @@
# by executing the WPS protocol.
#wps_priority=0
+# Device Provisioning Protocol (DPP) parameters
+#
+# How to process DPP configuration
+# 0 = report received configuration to an external program for
+# processing; do not generate any network profile internally (default)
+# 1 = report received configuration to an external program and generate
+# a network profile internally, but do not automatically connect
+# to the created (disabled) profile; the network profile id is
+# reported to external programs
+# 2 = report received configuration to an external program, generate
+# a network profile internally, try to connect to the created
+# profile automatically
+#dpp_config_processing=0
+#
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+#
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
# Maximum number of BSS entries to keep in memory
# Default: 200
# This can be used to limit memory use on the BSS entries (cached scan
@@ -405,6 +425,14 @@
# 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
@@ -1323,6 +1351,12 @@
# certificate. See altsubject_match documentation for more details.
# domain_suffix_match2: Constraint for server domain name. See
# domain_suffix_match for more details.
+# ocsp2: See ocsp for more details.
+#
+# Separate machine credentials can be configured for EAP-TEAP Phase 2 with
+# "machine_" prefix (e.g., "machine_identity") in the configuration parameters.
+# See the parameters without that prefix for more details on the meaning and
+# format of each such parameter.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
@@ -1522,6 +1556,16 @@
# 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 e59cf30..c5d2535 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -614,6 +614,9 @@
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;
@@ -700,6 +703,10 @@
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
+ int *last_scan_freqs;
+ unsigned int num_last_scan_freqs;
+ unsigned int suitable_network;
+ unsigned int no_suitable_network;
u64 drv_flags;
unsigned int drv_enc;
@@ -752,6 +759,7 @@
unsigned int connection_ht:1;
unsigned int connection_vht:1;
unsigned int connection_he:1;
+ unsigned int disable_mbo_oce:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -805,6 +813,7 @@
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 */
@@ -1239,6 +1248,8 @@
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+ u8 dpp_last_ssid[SSID_MAX_LEN];
+ size_t dpp_last_ssid_len;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
#endif /* CONFIG_DPP2 */
@@ -1256,6 +1267,7 @@
unsigned int ieee80211ac:1;
unsigned int enabled_4addr_mode:1;
unsigned int multi_bss_support:1;
+ unsigned int drv_authorized_port:1;
};
@@ -1391,6 +1403,8 @@
int add_oce_capa);
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid);
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
enum mbo_attr_id attr);
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
@@ -1414,11 +1428,12 @@
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);
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s);
int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
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 @@
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;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 5da8154..f51340f 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -533,9 +533,7 @@
if (wpa_s->conf->wps_cred_add_sae &&
cred->key_len != 2 * PMK_LEN) {
ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
-#endif /* CONFIG_IEEE80211W */
}
ssid->proto = WPA_PROTO_RSN;
break;
@@ -2691,7 +2689,7 @@
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_50GHZ))
freq = 5000 + 5 * chan;
- else if (chan >= 1 && chan <= 4 &&
+ else if (chan >= 1 && chan <= 6 &&
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_60GHZ))
freq = 56160 + 2160 * chan;