From a04bd250fff00c837f5bdccd28528853295da1e5 Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Mon, 2 May 2022 22:54:18 -0700 Subject: [PATCH] [wpa_supplicant] Cumulative patch from commit 27e828d72 Bug: 231272394 Test: connect/disconnect to WPA2, WPA3 networks Test: SoftAp & p2p connection Test: Regression test(b/231636895) BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open source 27e828d72 ACS: Send EHT enabled info to driver 82066bd36 nl80211: Don't force VHT channel definition with EHT 43fe1ce35 EHT: Add [EHT] flag into AP mode STA command 696ad5c2d EHT: Indicate wifi_generation=7 in wpa_supplicant STATUS output 4994c41f2 EHT: Indicate ieee80211be configuration in hostapd STATUS output 50d883710 EHT: Fix invalid length checking for EHT Capability element 6c7b2be42 SAE: Send real status code to the driver when AP rejects external auth 2c78f11a9 Fix compilation due to forward declaration of macaddr_acl c8e822801 OpenSSL: Fix build with old library versions that do not support TLS 1.3 c24e18e5c LibreSSL: Fix compilation issue with TLS 1.3 session ticket limit eb5e63985 LibreSSL: Fix compilation issue with RSA-OAEP 5d56cf1c7 BoringSSL: Fix compilation error due to TLS 1.3 session tickets a561d12d2 EAP peer status notification for server not supporting RFC 5746 566ce69a8 EAP peer: Workaround for servers that do not support safe TLS renegotiation ccb3206b6 Fix tls_connection_set_success_data() in TLS library wrappers decac7cd1 OpenSSL: Do not send out a TLS 1.3 session ticket if caching disabled 05406f7ae EAP-PEAP server: Fix TLS 1.3 move to Phase 2 without a new session ticket 10746875e OpenSSL: Allow no OCSP response when resuming a session with TLS 1.3 2be1bcaf7 EAP-TLS peer: Fix protected success indication check for resumed session 1c66276d9 EAP-TLS server: Send final TLS message for resumed session with TLS 1.3 81e249888 OpenSSL: Limit the number of TLS 1.3 session tickets to one d26247c3d wpa_supplicant/README-WPS: Beautifications a8d058c93 OpenSSL: SSLKEYLOGFILE capability to allow Wireshark TLS decoding 23f389068 wolfSSL: Fix OCSP stapling a2971f8d8 wolfSSL: Allow TLS version 1.3 to be disabled a40e48fbe wolfSSL: Fix TLS 1.3 session handling 0c3f68f2a wolfSSL: Check for the too-short-password error in pbkdf2_sha1() ca2622481 Check the return of pbkdf2_sha1() for errors 013cd694d wolfSSL: Fixes for FIPS builds 9d5f8168f wolfSSL: Register a FIPS callback 8f36e6c0f wolfSSL: Implement crypto_ec_key wrappers 1f7e10177 wolfSSL: Add missing free calls for wolfSSL structs ec1cd91e7 wolfSSL: Support both DER and PEM blobs 42871a5d2 EAP-SIM/AKA peer: IMSI privacy 21098e39f EAP-SIM/AKA server: IMSI privacy 36b11bbcf OpenSSL: RSA-OAEP-SHA-256 encryption/decryption c3d389b72 EHT: Channel switch command support dae7940a4 EHT: Additions to hostapd_set_freq_params() e646b11fe EHT: Indicate EHT support in Neighbor Report element f915d52de EHT: Provide EHT capabilities in STA addition path a6d1b4c46 EHT: Process (Re)Association Request frame capabilities 340c0e212 EHT: Parse elements received in Management frames d54e3d049 EHT: Add operation element in AP mode Management frames 9b7202d66 EHT: Add capabilities element in AP mode Management frames a7ea72188 EHT: Add configuration options for beamforming capabilities 8db3881c7 EHT: Add operating channel width configuration 8dcc2139f EHT: AP mode configuration options to enable/disable the support 9f7da264b nl80211: Pass station's EHT capabilities to the driver in sta_add() 0c8a9aa5d nl80211: Parse EHT capabilities from the driver c08b735fd EHT: Define EHT elements 1a716f86a defconfig: Document IEEE 802.11ax as a published amendment 86310c220 Set hostapd hw_mode automatically based on 6 GHz op_class 664fd83d5 nl80211: Increase the buffer length for debug printing channels 563162a5f QCA vendor attribute to allow eMLSR HW mode 1e34bc49c OpenSSL: Track SSL_SESSION ex data separately 734fa392f MBO: Check association disallowed in Beacon frames, if newer 284e3ad19 Determine whether Beacon frame information is newer in scan results 28c9f29a3 scan: Print SSID in scan results dump 5a0471579 Install wpa_passphrase when not disabled f1686d776 hostapd: Allow enabling background radar 08d7738bb wolfSSL: Speed up crypto_ec_point_compute_y_sqr() f50d5c9a8 wolfSSL: Fix crypto_ec_point_compute_y_sqr() error case processing 7302aa761 wolfSSL: Fix the memory leak of crypto_ec_point_compute_y_sqr() e7dd0fff1 wolfSSL: Use wc_HmacInit() to avoid potential use of uninitialized values f7be558d6 OpenSSL: Fix build with BoringSSL 6d33ef362 OpenSSL: Remove compatibility options for older versions than 1.0.2 78c2a4cd0 OpenSSL: Drop compatibility options for LibreSSL older than 2.7 b06250767 OpenSSL: Implement crypto_ecdh routines without EC_KEY for OpenSSL 3.0 fc96f6802 OpenSSL: Use new name for the EC_POINT set/get coordinate functions 0aae045af ctrl: Print the source address of the received commands f94214968 wpa_ctrl: Wait for a total of 10 seconds, not 10 seconds per iteration 0d9be8855 wolfSSL: Fix certificate commonName checking 94e0f39d9 wolfSSL: Use wolfSSL_export_keying_material() when available c31fc7a64 wolfSSL: Fix crypto_dh_init() and dh5_init() d7b8c6eef wolfSSL: Fix crypto_ecdh_* with ECC_TIMING_RESISTANT ae1fb6455 EAP-EKE server: Fix a memory leak on an error path 166acab4e wolfSSL: TLS session caching 12dee16d7 wolfSSL: Add a debug logging callback a5d190650 wolfSSL: Implement tls_get_tls_unique() a419fef36 wolfSSL: Implement tls_connection_get_cipher_suite() 364876b7d wolfSSL: Implement tls_connection_get_peer_subject() d9c716400 wolfSSL: Implement tls_connection_get_own_cert_used() d677b9dc6 wolfSSL: Conditional build for aes_wrap/aes_unwrap() b0f016b87 eapol_test: Update with src/ap/ieee802_1x.c changes 747c5f228 Include MS_FUNCS=y for EAP-pwd peer build c7f71fb86 Include HMAC-SHA384/512 KDF for SAE if SHA384/512 is included 3a759dcc8 ACS: Honor acs_exclude_dfs with hostapd's ACS implementation 3240cedd6 eapol_test: Print out names for additional known EAP types f5c711c85 OpenSSL: Unload providers only at process exit 33c4dd26c BSS coloring: Handle the collision and CCA events coming from the kernel 27b4cc712 nl80211: Handle driver events for BSS coloring 399d6e64d nl80211: Add the switch_color() handler for BSS color changes 86bd90eb3 BSS coloring: Disable BSS color during CCA f7d0b740e BSS coloring: BSS Color Change Announcement element generation 654d2395d BSS coloring: Handling of collision events and triggering CCA 52e2516f1 wpa_supplicant: Add the CONFIG_HE_OVERRIDES option to the defconfig 6a2a60f1d OpenSSL: Do not use the deprecated RSAPrivateKey function ebb3055e1 OpenSSL: Generate DH parameters automatically if not set with dh_file bcd299b32 OpenSSL: Convert DH/DSA parameter loading to new API 28c1c91d0 Remove unused dh_blob parameter 4a774cf31 Remove useless DH file configuration from TLS library wrappers 65652c67f Remove DH file configuration from TLS client functionality b94371af8 RADIUS attributes for EAPOL-Key message details 24763e3cd RADIUS: Attributes with Extended Types (RFC 6929) feed2f9e7 BoringSSL: Use accessor functions for X509 key usage flags 80be88a08 BoringSSL: Replace stack-allocated X509_STORE_CTX with heap one b95ed17f6 OpenSSL: Fix build with BoringSSL and LibreSSL 3.3.x and older ae0f6ee97 OpenSSL: CMAC using the OpenSSL library for non-FIPS cases as well 0c61f6234 OpenSSL: Implement CMAC using the EVP_MAC API 4fcd29660 OpenSSL: Extend CMAC to support 192-bit AES 117617843 OpenSSL: Remove now unused compatibility wrapper for RSA_bits() a2dbb2558 Android: Compile hs20-osu-client to /vendor/bin in test builds b0769ce61 DPP: Allow a list of supported curves to be used in bootstrapping URI ef85328a6 QCA vendor command support to reset configuration for eLNA bypass 7008c50fa OpenSSL: Implement DH using the EVP API e31500ade OpenSSL: Implement HMAC using the EVP_MAC API 097ca6bf0 OpenSSL: Unload providers on deinit 092efd45a OpenSSL: Implement AES keywrap using the EVP API 7e4984d9c OpenSSL: Use a correct EVP_CIPHER_CTX freeing function on an error path 8e0ac5366 RRM: Include passive channels in active beacon report scan 0adc67612 wpa_supplicant: Use unique IDs for networks and credentials dacb6d278 Update IEEE P802.11ax draft references to published amendment 8128ea76a Add Transmit Power Envelope element in 6 GHz bc3dc72a3 Extend 6 GHz Operation Info field in HE Operation element 0eb686637 hostapd: Add config option to specify 6 GHz regulatory AP type ee06165e9 hostapd: Extend Country element to support 6 GHz band f5ad97245 PASN: Fix build without CONFIG_TESTING_OPTIONS=y 3467a701c wpa_supplicant: Do not associate on 6 GHz with forbidden configurations 43c6eb5e4 SAE-PK: Add the option to the defconfigs 0482251a6 EAP-TLS: Allow TLSv1.3 support to be enabled with build config 7114e5606 EAP-TLS: Testing functionality to skip protected success indication 95fd54b86 Disconnect STA on continuous EAP reauth without 4-way handshake completion 9e11e746f EAP-TLS: Do not allow TLSv1.3 success without protected result indication 6135a8a6a Stop authentication attemps if AP does not disconnect us 88ab59d71 EAP-TLS: Replace the Commitment Message term with RFC 9190 language 63f311b10 EAP-TLS: Update specification references to RFC 5216 and 9190 5ab385321 Revert "Android: Compile hs20-osu-client to /vendor/bin in test builds" b746cb28b Add support for not transmitting EAPOL-Key group msg 2/2 d27f7bd94 FILS: Fix config check to allow unsolicited broadcast Probe Response 65a3a273c OWE: Reuse own DH private key in AP if STA tries OWE association again 6ff8bda99 hostapd: Add the missing CONFIG_SAE option to the defconfig 1f5b6085c Fix SIGSEGV of eapol_test 576662d27 ieee802_11_auth: Coding style cleanup - NULL comparison 945acf3ef ieee802_11_auth: Coding style cleanup - no string constant splitting 1c3438fec RADIUS ACL/PSK check during 4-way handshake 5b5c954c0 Fix AP config check to recognize all PSK AKMs c5d9f9064 QCA vendor attribute to indicate NDP interface managemtn using nl80211 a9c90475b FT: Update current_bss to target AP before check for SME-in-driver 0c88d1487 Debug print on CONFIG_NO_TKIP=y prevent RSNE with TKIP as group cipher d5a9331f9 P2P: Copy only valid opclasses while filtering out 6 GHz channels 99c91beaa Sync with wireless-next.git include/uapi/linux/nl80211.h d9121335a wpa_cli: Add ACL and BTM control commands 00622fcfe Extend ACL to install allow/deny list to the driver dynamically 077bce96f Set drv_max_acl_mac_addrs in wpa_supplicant AP mode 9828aba16 Support ACL operations in wpa_supplicant AP mode fd0d738ff Add return value to ACL functions f5ac42811 Move ACL control interface commands into shared files 930695662 Add BSS-TM-QUERY event to indicate reception of BSS TM Query febcdf324 Support BTM operations in wpa_supplicant AP mode 0f8c6e995 Move BTM control interface commands into shared file e059d8ece Update the Extended Capability element to struct sta_info eb2e6b56b Enable BSS Transition Management in wpa_supplicant AP mode 30ecf0181 DPP: Update Controller parameters when it was already started b93d1083e DPP: Fix msg_ctx for PKEX over TCP as Controller/Responder 3085e1a67 hs20-osu-client: dNSName values from OSU server certificate for PPS MO ce86f2446 DFS: Remove unnecessary variable 760a5ae26 DFS: Switch to background radar channel if available b63d953fe DFS: Enable CSA for background radar detection 25663241c DFS: Introduce hostapd_dfs_request_channel_switch() 316a9dc63 DFS: Configure background radar/CAC detection bad12effe nl80211: Radar background flag setting effd6111b DFS: Rely on channel_type in dfs_downgrade_bandwidth() f9ba3d5c8 OpenSSL 3.0: Set SSL groups using SSL_set1_groups() 09c62aaf1 OpenSSL: Determine RSA key size without low-level routines b700a56e1 OpenSSL 3.0: Determine the prime length for an EC key group using EVP_PKEY 3c61f4db4 OpenSSL: Replace EC_GROUP_get_curve_GFp() calls with EC_GROUP_get_curve() e2cb0ca1a OpenSSL 3.0: Implement crypto_ec_key_group() with new API f6a53f64a OpenSSL: Replace EVP_PKEY_cmp() with EVP_PKEY_eq() when available 5b093570d D-Bus: Add 'wep_disabled' capability 56a14cc72 DFS: Don't let cac_time_left_seconds overflow ae512c30a DPP: Fix uninitialised variable on error path 3a157fe92 dbus: Set CurrentAuthMode to INACTIVE only if network is not selected 0ce8d55a2 hs20-osu-client: Allow EST server to use different host name 5eaf596e1 HTTP: Make URL available to the cert_cb abed7978f HS 2.0 server: Event log entry on missing configuration for the realm 1192d5721 Android: Compile hs20-osu-client to /vendor/bin in test builds 1fee1c40c Enhance QCA vendor interface to indicate TWT required capability of AP a192305a4 Add QCA vendor attributes for AFC support in external ACS de5939ef5 DPP: Allow Configurator net_access_key_curve to be changed 9638452a6 DPP: Update Configurator to require same netAccessKey curve to be used 2b406eece DPP: Update Auth-I derivation operations de64dfe98 DPP: Curve change for netAccessKey fd2eb7a41 DPP: Fix a memory leak on error path e9551efe0 DPP: Missing/invalid Protocol Version in Reconfig Auth Req eeb72e7c9 DPP: Extend DPP_PKEX_ADD ver=<1/2> to cover Responder role 6c3c431bb Add QCA vendor attribute to enable Spectral FFT recapture fcbdaae8a SAE: Add support for RADIUS passphrase as the SAE password 3d86fcee0 cleanup: Remove unreachable code 9683195ee qca-vendor: Fix typos 4c9ef9322 brcm_vendor: Fix typos d65285ab8 src/drivers: Fix typos 203a027b2 nl80211: Report background radar/CAC detection capability 0a73649b6 DFS: Add capability to select radar-only channels f39765369 DFS: Introduce dfs_set_valid_channel() utility routine d001b301b Fix removal of wpa_passphrase on 'make clean' cb41c214b build: Re-enable options for libwpa_client.so and wpa_passphrase dec626109 HE: Fix invalid length checking for HE Capability element 53be64f7d HE: Fix calculation of the PPE Threshold field length 738fef2f0 Clear PSK explicitly from memory in couple more cases on deinit 567b9764f Clear PMK explicitly even without FT support in AP build 0bd29c176 Remove duplicated pointer check 007fd6111 Clear temporary results from stack in PBKDF2-SHA1 1364f322b Remove GTK/IGTK/BIGTK from memory explicitly in AP mode af1f0694e Clear last set keys (for testing purposes) from memory explicitly 6c850a1c0 nl80211: Clear bss->freq when stopping AP mode a44fa15cb Define a vendor specific NDP attribute for NAN service id 414ca953f DPP: Clear SCANNING state when starting network introduction 0b5f8e3d8 DPP: Clear netrole on starting chirping or reconfiguration 2fcc076d1 Clear wpa_s->last/current_ssid in more cases 7a7f803a9 DPP: Stop offchannel frame TX wait on DPP_STOP_LISTEN in a corner case 7e941e7a1 macsec_linux: Support cipher suite configuration 46c635910 MACsec: Support GCM-AES-256 cipher suite 42944de69 nl80211: Do not store no-wait TX frame cookies to be cancelled 340ec48cd DPP: Clear state on configuration failure in GAS server hander 7e6f59c70 nl80211: Clear the last saved TX frame cookie on wait expiration 9d5fd3328 Update QCA vendor attribute to indicate maximum PCL attributes 19169a53a atheros: Do not include p2p.h f43d31dda nl80211: Debug print association comeback event data a91072503 OCV: Don't start SA Query timer on CSA when SA Query is offloaded f5c8697c0 Sync with mac80211-next.git include/uapi/linux/nl80211.h 632a9995c Clear ignore_old_scan_res on FLUSH command Change-Id: I35fd1fb999d045ced8c153fe3d8284c9a71069b1 --- Android.mk | 11 +- hostapd/Android.bp | 1 - hostapd/Android.mk | 9 + hostapd/Makefile | 9 + hostapd/config_file.c | 85 +- hostapd/config_file.h | 5 - hostapd/ctrl_iface.c | 377 +-------- hostapd/defconfig | 14 +- hostapd/hostapd.conf | 75 +- hostapd/hostapd_cli.c | 2 +- hostapd/main.c | 3 +- hs20/client/Android.mk | 10 + hs20/client/osu_client.c | 26 +- hs20/client/spp_client.c | 1 - hs20/server/spp_server.c | 5 +- src/ap/acs.c | 12 +- src/ap/ap_config.c | 88 ++- src/ap/ap_config.h | 74 +- src/ap/ap_drv_ops.c | 36 +- src/ap/ap_drv_ops.h | 22 +- src/ap/authsrv.c | 29 + src/ap/beacon.c | 147 +++- src/ap/ctrl_iface_ap.c | 374 ++++++++- src/ap/ctrl_iface_ap.h | 17 + src/ap/dfs.c | 520 +++++++++---- src/ap/dpp_hostapd.c | 97 ++- src/ap/drv_callbacks.c | 56 +- src/ap/hostapd.c | 171 ++++- src/ap/hostapd.h | 34 + src/ap/ieee802_11.c | 193 +++-- src/ap/ieee802_11.h | 18 + src/ap/ieee802_11_auth.c | 150 +++- src/ap/ieee802_11_auth.h | 5 +- src/ap/ieee802_11_eht.c | 353 +++++++++ src/ap/ieee802_11_he.c | 55 +- src/ap/ieee802_11_shared.c | 26 + src/ap/ieee802_1x.c | 3 + src/ap/neighbor_db.c | 7 +- src/ap/sta_info.c | 9 +- src/ap/sta_info.h | 3 + src/ap/wnm_ap.c | 13 + src/ap/wpa_auth.c | 86 ++- src/ap/wpa_auth.h | 9 +- src/ap/wpa_auth_ft.c | 1 + src/ap/wpa_auth_glue.c | 43 +- src/ap/wpa_auth_i.h | 3 + src/ap/wpa_auth_kay.c | 5 +- src/ap/wps_hostapd.c | 3 +- src/common/brcm_vendor.h | 8 +- src/common/dpp.c | 446 ++++++++++- src/common/dpp.h | 26 + src/common/dpp_crypto.c | 91 +++ src/common/dpp_i.h | 1 + src/common/dpp_reconfig.c | 18 +- src/common/dpp_tcp.c | 65 +- src/common/hw_features_common.c | 28 +- src/common/hw_features_common.h | 5 +- src/common/ieee802_11_common.c | 10 +- src/common/ieee802_11_common.h | 4 + src/common/ieee802_11_defs.h | 163 +++- src/common/qca-vendor.h | 160 +++- src/common/wpa_common.c | 7 + src/common/wpa_ctrl.c | 16 +- src/common/wpa_ctrl.h | 3 + src/crypto/crypto.h | 42 + src/crypto/crypto_gnutls.c | 5 + src/crypto/crypto_internal.c | 5 + src/crypto/crypto_libtomcrypt.c | 5 + src/crypto/crypto_linux.c | 5 + src/crypto/crypto_nettle.c | 5 + src/crypto/crypto_none.c | 5 + src/crypto/crypto_openssl.c | 978 ++++++++++++++++++++++-- src/crypto/crypto_wolfssl.c | 356 ++++++++- src/crypto/sha1-pbkdf2.c | 3 + src/crypto/tls.h | 8 +- src/crypto/tls_gnutls.c | 1 + src/crypto/tls_internal.c | 11 +- src/crypto/tls_none.c | 1 + src/crypto/tls_openssl.c | 495 ++++++++---- src/crypto/tls_openssl_ocsp.c | 8 +- src/crypto/tls_wolfssl.c | 256 +++++-- src/drivers/driver.h | 102 ++- src/drivers/driver_atheros.c | 1 - src/drivers/driver_common.c | 4 + src/drivers/driver_macsec_linux.c | 25 +- src/drivers/driver_macsec_qca.c | 2 +- src/drivers/driver_nl80211.c | 149 +++- src/drivers/driver_nl80211_capa.c | 64 +- src/drivers/driver_nl80211_event.c | 98 ++- src/drivers/driver_nl80211_scan.c | 5 +- src/drivers/ndis_events.c | 5 +- src/drivers/nl80211_copy.h | 327 +++++++- src/eap_common/eap_defs.h | 2 +- src/eap_peer/eap.c | 31 + src/eap_peer/eap_aka.c | 83 ++ src/eap_peer/eap_config.h | 28 +- src/eap_peer/eap_sim.c | 84 ++ src/eap_peer/eap_tls.c | 15 +- src/eap_peer/eap_tls_common.c | 21 +- src/eap_peer/eap_ttls.c | 4 +- src/eap_server/eap.h | 7 + src/eap_server/eap_server_aka.c | 83 +- src/eap_server/eap_server_eke.c | 1 + src/eap_server/eap_server_peap.c | 18 + src/eap_server/eap_server_sim.c | 69 ++ src/eap_server/eap_server_tls.c | 10 +- src/eap_server/eap_server_tls_common.c | 18 +- src/eap_server/eap_tls_common.h | 2 + src/eapol_auth/eapol_auth_sm.h | 1 + src/p2p/p2p_utils.c | 2 +- src/pae/ieee802_1x_cp.c | 8 +- src/pae/ieee802_1x_kay.c | 17 +- src/pae/ieee802_1x_kay.h | 3 +- src/radius/radius.c | 195 ++++- src/radius/radius.h | 33 +- src/rsn_supp/wpa.c | 10 + src/rsn_supp/wpa.h | 1 + src/rsn_supp/wpa_i.h | 1 + src/utils/common.c | 2 +- src/utils/common.h | 1 + src/utils/http-utils.h | 1 + src/utils/http_curl.c | 50 +- wpa_supplicant/Android.bp | 1 - wpa_supplicant/Android.mk | 28 +- wpa_supplicant/Makefile | 51 +- wpa_supplicant/README-HS20 | 6 + wpa_supplicant/README-WPS | 24 +- wpa_supplicant/ap.c | 183 +++++ wpa_supplicant/ap.h | 18 + wpa_supplicant/bss.c | 1 + wpa_supplicant/bss.h | 2 + wpa_supplicant/config.c | 50 +- wpa_supplicant/config.h | 10 + wpa_supplicant/config_file.c | 8 +- wpa_supplicant/config_ssid.h | 7 + wpa_supplicant/config_winreg.c | 2 - wpa_supplicant/ctrl_iface.c | 91 ++- wpa_supplicant/ctrl_iface.h | 2 + wpa_supplicant/ctrl_iface_udp.c | 3 + wpa_supplicant/ctrl_iface_unix.c | 3 + wpa_supplicant/dbus/dbus_new_handlers.c | 7 +- wpa_supplicant/defconfig | 19 + wpa_supplicant/dpp_supplicant.c | 107 ++- wpa_supplicant/eapol_test.c | 62 +- wpa_supplicant/events.c | 89 ++- wpa_supplicant/interworking.c | 6 + wpa_supplicant/main.c | 2 + wpa_supplicant/mbo.c | 25 +- wpa_supplicant/mesh.c | 3 +- wpa_supplicant/notify.c | 4 + wpa_supplicant/p2p_supplicant.c | 2 +- wpa_supplicant/pasn_supplicant.c | 12 +- wpa_supplicant/preauth_test.c | 2 + wpa_supplicant/rrm.c | 28 +- wpa_supplicant/scan.c | 25 +- wpa_supplicant/sme.c | 7 +- wpa_supplicant/wpa_cli.c | 55 +- wpa_supplicant/wpa_passphrase.c | 6 +- wpa_supplicant/wpa_supplicant.c | 41 +- wpa_supplicant/wpa_supplicant.conf | 13 +- wpa_supplicant/wpa_supplicant_i.h | 9 +- wpa_supplicant/wpas_glue.c | 10 +- wpa_supplicant/wpas_kay.c | 5 +- wpa_supplicant/wps_supplicant.c | 2 - 164 files changed, 7624 insertions(+), 1525 deletions(-) create mode 100644 src/ap/ieee802_11_eht.c diff --git a/Android.mk b/Android.mk index bd7a4097..bb8326cb 100644 --- a/Android.mk +++ b/Android.mk @@ -1,10 +1,15 @@ -LOCAL_PATH:= $(call my-dir) +S_LOCAL_PATH := $(call my-dir) ifneq ($(filter VER_0_8_X VER_2_1_DEVEL,$(WPA_SUPPLICANT_VERSION)),) # The order of the 2 Android.mks does matter! # TODO: Clean up the Android.mks, reset all the temporary variables at the # end of each Android.mk, so that one Android.mk doesn't depend on variables # set up in the other Android.mk. -include $(LOCAL_PATH)/hostapd/Android.mk \ - $(LOCAL_PATH)/wpa_supplicant/Android.mk +include $(S_LOCAL_PATH)/hostapd/Android.mk \ + $(S_LOCAL_PATH)/wpa_supplicant/Android.mk +ifneq ($(TARGET_BUILD_VARIANT), user) +ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0) +include $(S_LOCAL_PATH)/hs20/client/Android.mk +endif #End of Check for platform version +endif #End of Check for target build variant endif diff --git a/hostapd/Android.bp b/hostapd/Android.bp index d7cc39b9..2a252080 100644 --- a/hostapd/Android.bp +++ b/hostapd/Android.bp @@ -287,7 +287,6 @@ filegroup { "src/crypto/fips_prf_openssl.c", "src/crypto/aes-siv.c", "src/crypto/aes-ctr.c", - "src/crypto/aes-omac1.c", "src/crypto/sha1-prf.c", "src/crypto/sha1-tlsprf.c", "src/crypto/sha256-prf.c", diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 4c37b77a..adb4c084 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -314,6 +314,12 @@ ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +L_CFLAGS += -DCONFIG_IEEE80211BE +OBJS += src/ap/ieee802_11_eht.c +endif + ifdef CONFIG_IEEE80211AX L_CFLAGS += -DCONFIG_IEEE80211AX endif @@ -673,6 +679,7 @@ L_CFLAGS += -DCONFIG_TLSV12 endif ifeq ($(CONFIG_TLS), openssl) +L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ifdef TLS_FUNCS OBJS += src/crypto/tls_openssl.c OBJS += src/crypto/tls_openssl_ocsp.c @@ -845,7 +852,9 @@ endif ifdef NEED_AES_ENCBLOCK AESOBJS += src/crypto/aes-encblock.c endif +ifneq ($(CONFIG_TLS), openssl) AESOBJS += src/crypto/aes-omac1.c +endif ifdef NEED_AES_UNWRAP ifneq ($(CONFIG_TLS), openssl) NEED_AES_DEC=y diff --git a/hostapd/Makefile b/hostapd/Makefile index 98a0102a..5f063786 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -343,6 +343,12 @@ ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +CFLAGS += -DCONFIG_IEEE80211BE +OBJS += ../src/ap/ieee802_11_eht.o +endif + ifdef CONFIG_IEEE80211AX CFLAGS += -DCONFIG_IEEE80211AX OBJS += ../src/ap/ieee802_11_he.o @@ -712,6 +718,7 @@ endif endif ifeq ($(CONFIG_TLS), openssl) +CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 CONFIG_CRYPTO=openssl ifdef TLS_FUNCS OBJS += ../src/crypto/tls_openssl.o @@ -936,11 +943,13 @@ endif ifdef NEED_AES_ENCBLOCK AESOBJS += ../src/crypto/aes-encblock.o endif +ifneq ($(CONFIG_TLS), openssl) 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) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 7e605ffc..2d5a510c 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -118,52 +118,6 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, #endif /* CONFIG_NO_VLAN */ -int hostapd_acl_comp(const void *a, const void *b) -{ - const struct mac_acl_entry *aa = a; - const struct mac_acl_entry *bb = b; - return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); -} - - -int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, - int vlan_id, const u8 *addr) -{ - struct mac_acl_entry *newacl; - - newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); - if (!newacl) { - wpa_printf(MSG_ERROR, "MAC list reallocation failed"); - return -1; - } - - *acl = newacl; - os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); - os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id)); - (*acl)[*num].vlan_id.untagged = vlan_id; - (*acl)[*num].vlan_id.notempty = !!vlan_id; - (*num)++; - - return 0; -} - - -void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, - const u8 *addr) -{ - int i = 0; - - while (i < *num) { - if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) { - os_remove_in_array(*acl, *num, sizeof(**acl), i); - (*num)--; - } else { - i++; - } - } -} - - static int hostapd_config_read_maclist(const char *fname, struct mac_acl_entry **acl, int *num) { @@ -2635,6 +2589,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->eap_sim_aka_result_ind = atoi(pos); } else if (os_strcmp(buf, "eap_sim_id") == 0) { bss->eap_sim_id = atoi(pos); + } else if (os_strcmp(buf, "imsi_privacy_key") == 0) { + os_free(bss->imsi_privacy_key); + bss->imsi_privacy_key = os_strdup(pos); #endif /* EAP_SERVER_SIM */ #ifdef EAP_SERVER_TNC } else if (os_strcmp(buf, "tnc") == 0) { @@ -2975,7 +2932,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->wpa_psk_radius = atoi(pos); if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED && bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED && - bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) { + bss->wpa_psk_radius != PSK_RADIUS_REQUIRED && + bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS) { wpa_printf(MSG_ERROR, "Line %d: unknown wpa_psk_radius %d", line, bss->wpa_psk_radius); @@ -3139,6 +3097,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + conf->hw_mode_set = true; } else if (os_strcmp(buf, "wps_rf_bands") == 0) { if (os_strcmp(pos, "ad") == 0) bss->wps_rf_bands = WPS_RF_60GHZ; @@ -3193,6 +3152,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->acs_freq_list_present = 1; } else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) { conf->acs_exclude_6ghz_non_psc = atoi(pos); + } else if (os_strcmp(buf, "enable_background_radar") == 0) { + conf->enable_background_radar = atoi(pos); } else if (os_strcmp(buf, "min_tx_power") == 0) { int val = atoi(pos); @@ -3642,6 +3603,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "he_6ghz_reg_pwr_type") == 0) { + conf->he_6ghz_reg_pwr_type = atoi(pos); } else if (os_strcmp(buf, "he_oper_chwidth") == 0) { conf->he_oper_chwidth = atoi(pos); } else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) { @@ -4301,6 +4264,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->skip_send_eapol = atoi(pos); } else if (os_strcmp(buf, "enable_eapol_large_timeout") == 0) { conf->enable_eapol_large_timeout = atoi(pos); + } else if (os_strcmp(buf, "eap_skip_prot_success") == 0) { + bss->eap_skip_prot_success = atoi(pos); #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_SAE } else if (os_strcmp(buf, "sae_password") == 0) { @@ -4665,6 +4630,16 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } bss->mka_priority = mka_priority; + } else if (os_strcmp(buf, "macsec_csindex") == 0) { + int macsec_csindex = atoi(pos); + + if (macsec_csindex < 0 || macsec_csindex > 1) { + wpa_printf(MSG_ERROR, + "Line %d: invalid macsec_csindex (%d): '%s'.", + line, macsec_csindex, pos); + return 1; + } + bss->macsec_csindex = macsec_csindex; } else if (os_strcmp(buf, "mka_cak") == 0) { size_t len = os_strlen(pos); @@ -4701,6 +4676,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->disable_11ac = !!atoi(pos); } else if (os_strcmp(buf, "disable_11ax") == 0) { bss->disable_11ax = !!atoi(pos); + } else if (os_strcmp(buf, "disable_11be") == 0) { + bss->disable_11be = !!atoi(pos); #ifdef CONFIG_PASN #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcmp(buf, "force_kdk_derivation") == 0) { @@ -4728,6 +4705,20 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } else if (os_strcmp(buf, "rnr") == 0) { bss->rnr = atoi(pos); +#ifdef CONFIG_IEEE80211BE + } else if (os_strcmp(buf, "ieee80211be") == 0) { + conf->ieee80211be = atoi(pos); + } else if (os_strcmp(buf, "eht_oper_chwidth") == 0) { + conf->eht_oper_chwidth = atoi(pos); + } else if (os_strcmp(buf, "eht_oper_centr_freq_seg0_idx") == 0) { + conf->eht_oper_centr_freq_seg0_idx = atoi(pos); + } else if (os_strcmp(buf, "eht_su_beamformer") == 0) { + conf->eht_phy_capab.su_beamformer = atoi(pos); + } else if (os_strcmp(buf, "eht_su_beamformee") == 0) { + conf->eht_phy_capab.su_beamformee = atoi(pos); + } else if (os_strcmp(buf, "eht_mu_beamformer") == 0) { + conf->eht_phy_capab.mu_beamformer = atoi(pos); +#endif /* CONFIG_IEEE80211BE */ } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", diff --git a/hostapd/config_file.h b/hostapd/config_file.h index 9830f5a2..c98bdb68 100644 --- a/hostapd/config_file.h +++ b/hostapd/config_file.h @@ -13,10 +13,5 @@ struct hostapd_config * hostapd_config_read(const char *fname); int hostapd_set_iface(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *field, char *value); -int hostapd_acl_comp(const void *a, const void *b); -int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, - int vlan_id, const u8 *addr); -void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, - const u8 *addr); #endif /* CONFIG_FILE_H */ diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index a62f3c7a..ad994d42 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -772,235 +772,6 @@ static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd, #ifdef CONFIG_WNM_AP -static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - int disassoc_timer; - struct sta_info *sta; - - if (hwaddr_aton(cmd, addr)) - return -1; - if (cmd[17] != ' ') - return -1; - disassoc_timer = atoi(cmd + 17); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR - " not found for disassociation imminent message", - MAC2STR(addr)); - return -1; - } - - return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); -} - - -static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - const char *url, *timerstr; - int disassoc_timer; - struct sta_info *sta; - - if (hwaddr_aton(cmd, addr)) - return -1; - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR - " not found for ESS disassociation imminent message", - MAC2STR(addr)); - return -1; - } - - timerstr = cmd + 17; - if (*timerstr != ' ') - return -1; - timerstr++; - disassoc_timer = atoi(timerstr); - if (disassoc_timer < 0 || disassoc_timer > 65535) - return -1; - - url = os_strchr(timerstr, ' '); - if (url == NULL) - return -1; - url++; - - return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); -} - - -static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - const char *pos, *end; - int disassoc_timer = 0; - struct sta_info *sta; - u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01; - u8 bss_term_dur[12]; - char *url = NULL; - int ret; - u8 nei_rep[1000]; - int nei_len; - u8 mbo[10]; - size_t mbo_len = 0; - - if (hwaddr_aton(cmd, addr)) { - wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); - return -1; - } - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR - " not found for BSS TM Request message", - MAC2STR(addr)); - return -1; - } - - pos = os_strstr(cmd, " disassoc_timer="); - if (pos) { - pos += 16; - disassoc_timer = atoi(pos); - if (disassoc_timer < 0 || disassoc_timer > 65535) { - wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); - return -1; - } - } - - pos = os_strstr(cmd, " valid_int="); - if (pos) { - pos += 11; - valid_int = atoi(pos); - } - - pos = os_strstr(cmd, " dialog_token="); - if (pos) { - pos += 14; - dialog_token = atoi(pos); - } - - pos = os_strstr(cmd, " bss_term="); - if (pos) { - pos += 10; - req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; - /* TODO: TSF configurable/learnable */ - bss_term_dur[0] = 4; /* Subelement ID */ - bss_term_dur[1] = 10; /* Length */ - os_memset(&bss_term_dur[2], 0, 8); - end = os_strchr(pos, ','); - if (end == NULL) { - wpa_printf(MSG_DEBUG, "Invalid bss_term data"); - return -1; - } - end++; - WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); - } - - nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep, - sizeof(nei_rep)); - if (nei_len < 0) - return -1; - - pos = os_strstr(cmd, " url="); - if (pos) { - size_t len; - pos += 5; - end = os_strchr(pos, ' '); - if (end) - len = end - pos; - else - len = os_strlen(pos); - url = os_malloc(len + 1); - if (url == NULL) - return -1; - os_memcpy(url, pos, len); - url[len] = '\0'; - req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - } - - if (os_strstr(cmd, " pref=1")) - req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; - if (os_strstr(cmd, " abridged=1")) - req_mode |= WNM_BSS_TM_REQ_ABRIDGED; - if (os_strstr(cmd, " disassoc_imminent=1")) - req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; - -#ifdef CONFIG_MBO - pos = os_strstr(cmd, "mbo="); - if (pos) { - unsigned int mbo_reason, cell_pref, reassoc_delay; - u8 *mbo_pos = mbo; - - ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason, - &reassoc_delay, &cell_pref); - if (ret != 3) { - wpa_printf(MSG_DEBUG, - "MBO requires three arguments: mbo=::"); - ret = -1; - goto fail; - } - - if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) { - wpa_printf(MSG_DEBUG, - "Invalid MBO transition reason code %u", - mbo_reason); - ret = -1; - goto fail; - } - - /* Valid values for Cellular preference are: 0, 1, 255 */ - if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) { - wpa_printf(MSG_DEBUG, - "Invalid MBO cellular capability %u", - cell_pref); - ret = -1; - goto fail; - } - - if (reassoc_delay > 65535 || - (reassoc_delay && - !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) { - wpa_printf(MSG_DEBUG, - "MBO: Assoc retry delay is only valid in disassoc imminent mode"); - ret = -1; - goto fail; - } - - *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON; - *mbo_pos++ = 1; - *mbo_pos++ = mbo_reason; - *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF; - *mbo_pos++ = 1; - *mbo_pos++ = cell_pref; - - if (reassoc_delay) { - *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY; - *mbo_pos++ = 2; - WPA_PUT_LE16(mbo_pos, reassoc_delay); - mbo_pos += 2; - } - - mbo_len = mbo_pos - mbo; - } -#endif /* CONFIG_MBO */ - - ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, - valid_int, bss_term_dur, dialog_token, url, - nei_len ? nei_rep : NULL, nei_len, - mbo_len ? mbo : NULL, mbo_len); -#ifdef CONFIG_MBO -fail: -#endif /* CONFIG_MBO */ - os_free(url); - return ret; -} - - static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd, const char *cmd) { @@ -1362,43 +1133,6 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, } -static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd) -{ - struct sta_info *sta; - struct vlan_description vlan_id; - - if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED) - return; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (!hostapd_maclist_found(hapd->conf->accept_mac, - hapd->conf->num_accept_mac, - sta->addr, &vlan_id) || - (vlan_id.notempty && - vlan_compare(&vlan_id, sta->vlan_desc))) - ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_UNSPECIFIED); - } -} - - -static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd) -{ - struct sta_info *sta; - struct vlan_description vlan_id; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (hostapd_maclist_found(hapd->conf->deny_mac, - hapd->conf->num_deny_mac, sta->addr, - &vlan_id) && - (!vlan_id.notempty || - !vlan_compare(&vlan_id, sta->vlan_desc))) - ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_UNSPECIFIED); - } -} - - static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd, const char *bands) { @@ -1519,6 +1253,9 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { os_free(hapd->dpp_configurator_params); hapd->dpp_configurator_params = os_strdup(value); +#ifdef CONFIG_DPP2 + dpp_controller_set_params(hapd->iface->interfaces->dpp, value); +#endif /* CONFIG_DPP2 */ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { hapd->dpp_init_max_tries = atoi(value); } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { @@ -2838,7 +2575,7 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, for (i = 0; i < iface->num_bss; i++) { - /* Save CHAN_SWITCH VHT and HE config */ + /* Save CHAN_SWITCH VHT, HE, and EHT config */ hostapd_chan_switch_config(iface->bss[i], &settings.freq_params); @@ -3383,80 +3120,6 @@ static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf, } -static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, - const char *txtaddr) -{ - u8 addr[ETH_ALEN]; - struct vlan_description vlan_id; - - if (!(*num)) - return 0; - - if (hwaddr_aton(txtaddr, addr)) - return -1; - - if (hostapd_maclist_found(*acl, *num, addr, &vlan_id)) - hostapd_remove_acl_mac(acl, num, addr); - - return 0; -} - - -static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, - int *num) -{ - while (*num) - hostapd_remove_acl_mac(acl, num, (*acl)[0].addr); -} - - -static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, - char *buf, size_t buflen) -{ - int i = 0, len = 0, ret = 0; - - if (!acl) - return 0; - - while (i < num) { - ret = os_snprintf(buf + len, buflen - len, - MACSTR " VLAN_ID=%d\n", - MAC2STR(acl[i].addr), - acl[i].vlan_id.untagged); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - i++; - len += ret; - } - return len; -} - - -static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - struct vlan_description vlan_id; - int ret = 0, vlanid = 0; - const char *pos; - - if (hwaddr_aton(cmd, addr)) - return -1; - - pos = os_strstr(cmd, "VLAN_ID="); - if (pos) - vlanid = atoi(pos + 8); - - if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) { - ret = hostapd_add_acl_maclist(acl, num, vlanid, addr); - if (ret != -1 && *acl) - qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); - } - - return ret < 0 ? -1 : 0; -} - - static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd, const char *field, char *buf, size_t buflen) @@ -3832,14 +3495,15 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) { if (hostapd_ctrl_iface_acl_add_mac( &hapd->conf->accept_mac, - &hapd->conf->num_accept_mac, buf + 19)) + &hapd->conf->num_accept_mac, buf + 19) || + hostapd_set_acl(hapd)) reply_len = -1; } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { - if (!hostapd_ctrl_iface_acl_del_mac( + if (hostapd_ctrl_iface_acl_del_mac( &hapd->conf->accept_mac, - &hapd->conf->num_accept_mac, buf + 19)) - hostapd_disassoc_accept_mac(hapd); - else + &hapd->conf->num_accept_mac, buf + 19) || + hostapd_set_acl(hapd) || + hostapd_disassoc_accept_mac(hapd)) reply_len = -1; } else if (os_strcmp(buf + 11, "SHOW") == 0) { reply_len = hostapd_ctrl_iface_acl_show_mac( @@ -3849,20 +3513,23 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, hostapd_ctrl_iface_acl_clear_list( &hapd->conf->accept_mac, &hapd->conf->num_accept_mac); - hostapd_disassoc_accept_mac(hapd); + if (hostapd_set_acl(hapd) || + hostapd_disassoc_accept_mac(hapd)) + reply_len = -1; } } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) { if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) { - if (!hostapd_ctrl_iface_acl_add_mac( + if (hostapd_ctrl_iface_acl_add_mac( &hapd->conf->deny_mac, - &hapd->conf->num_deny_mac, buf + 17)) - hostapd_disassoc_deny_mac(hapd); - else + &hapd->conf->num_deny_mac, buf + 17) || + hostapd_set_acl(hapd) || + hostapd_disassoc_deny_mac(hapd)) reply_len = -1; } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) { if (hostapd_ctrl_iface_acl_del_mac( &hapd->conf->deny_mac, - &hapd->conf->num_deny_mac, buf + 17)) + &hapd->conf->num_deny_mac, buf + 17) || + hostapd_set_acl(hapd)) reply_len = -1; } else if (os_strcmp(buf + 9, "SHOW") == 0) { reply_len = hostapd_ctrl_iface_acl_show_mac( @@ -3872,6 +3539,8 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, hostapd_ctrl_iface_acl_clear_list( &hapd->conf->deny_mac, &hapd->conf->num_deny_mac); + if (hostapd_set_acl(hapd)) + reply_len = -1; } #ifdef CONFIG_DPP } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) { @@ -3963,6 +3632,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) { + if (dpp_configurator_set(hapd->iface->interfaces->dpp, + buf + 20) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) { if (dpp_configurator_remove(hapd->iface->interfaces->dpp, buf + 24) < 0) diff --git a/hostapd/defconfig b/hostapd/defconfig index 2855acdf..6a41dcf0 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -156,10 +156,20 @@ CONFIG_IPV6=y #CONFIG_IEEE80211AC=y # IEEE 802.11ax HE support +#CONFIG_IEEE80211AX=y + +# IEEE 802.11be EHT support +# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE. # Note: This is experimental and work in progress. The definitions are still # subject to change and this should not be expected to interoperate with the -# final IEEE 802.11ax version. -#CONFIG_IEEE80211AX=y +# final IEEE 802.11be version. +#CONFIG_IEEE80211BE=y + +# Simultaneous Authentication of Equals (SAE), WPA3-Personal +#CONFIG_SAE=y + +# SAE Public Key, WPA3-Personal +#CONFIG_SAE_PK=y # Remove debugging code that is printing out debug messages to stdout. # This can be used to reduce the size of the hostapd considerably if debugging diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 3c2019f7..f37d5634 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -225,6 +225,16 @@ channel=1 # Default behavior is to include all PSC and non-PSC channels. #acs_exclude_6ghz_non_psc=1 +# Enable background radar feature +# This feature allows CAC to be run on dedicated radio RF chains while the +# radio(s) are otherwise running normal AP activities on other channels. +# This requires that the driver and the radio support it before feature will +# actually be enabled, i.e., this parameter value is ignored with drivers that +# do not advertise support for the capability. +# 0: Leave disabled (default) +# 1: Enable it. +#enable_background_radar=1 + # Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection. # (default 0, i.e., not constraint) #min_tx_power=20 @@ -965,6 +975,13 @@ wmm_ac_vo_acm=0 # (default) #he_6ghz_tx_ant_pat=1 +# 6 GHz Access Point type +# This config is to set the 6 GHz Access Point type. Possible options are: +# 0 = Indoor AP (default) +# 1 = Standard Power AP +# This has no impact for operation on other bands. +#he_6ghz_reg_pwr_type=0 + # Unsolicited broadcast Probe Response transmission settings # This is for the 6 GHz band only. If the interval is set to a non-zero value, # the AP schedules unsolicited broadcast Probe Response frames to be @@ -973,6 +990,40 @@ wmm_ac_vo_acm=0 # Valid range: 0..20 TUs; default is 0 (disabled) #unsol_bcast_probe_resp_interval=0 +##### IEEE 802.11be related configuration ##################################### + +#ieee80211be: Whether IEEE 802.11be (EHT) is enabled +# 0 = disabled (default) +# 1 = enabled +#ieee80211be=1 + +#disable_11be: Boolean (0/1) to disable EHT for a specific BSS +#disable_11be=0 + +#eht_su_beamformer: EHT single user beamformer support +# 0 = not supported (default) +# 1 = supported +#eht_su_beamformer=1 + +#eht_su_beamformee: EHT single user beamformee support +# 0 = not supported (default) +# 1 = supported +#eht_su_beamformee=1 + +#eht_mu_beamformer: EHT multiple user beamformer support +# 0 = not supported (default) +# 1 = supported +#eht_mu_beamformer=1 + +# EHT operating channel information; see matching he_* parameters for details. +# The field eht_oper_centr_freq_seg0_idx field is used to indicate center +# frequency of 40, 80, and 160 MHz bandwidth operation. +# In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is +# derived from the configured operating class (IEEE P802.11be/D1.5, +# Annex E.1 - Country information and operating classes). +#eht_oper_chwidth +#eht_oper_centr_freq_seg0_idx + ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization @@ -1070,6 +1121,10 @@ eapol_key_index_workaround=0 # mka_priority (Priority of MKA Actor) # Range: 0..255 (default: 255) # +# macsec_csindex: IEEE 802.1X/MACsec cipher suite +# 0 = GCM-AES-128 (default) +# 1 = GCM-AES-256 (default) +# # mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode # This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair. # In this mode, instances of hostapd can act as MACsec peers. The peer @@ -1243,12 +1298,11 @@ eap_server=0 # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an -# ephemeral DH key exchange. In most cases, the default RSA authentication does -# not use this configuration. However, it is possible setup RSA to use -# ephemeral DH key exchange. In addition, ciphers with DSA keys always use -# ephemeral DH keys. This can be used to achieve forward secrecy. If the file -# is in DSA parameters format, it will be automatically converted into DH -# params. This parameter is required if anonymous EAP-FAST is used. +# ephemeral DH key exchange. If the file is in DSA parameters format, it will +# be automatically converted into DH params. If the used TLS library supports +# automatic DH parameter selection, that functionality will be used if this +# parameter is not set. DH parameters are required if anonymous EAP-FAST is +# used. # You can generate DH parameters file with OpenSSL, e.g., # "openssl dhparam -out /etc/hostapd.dh.pem 2048" #dh_file=/etc/hostapd.dh.pem @@ -1369,6 +1423,10 @@ eap_server=0 # 3 = use pseudonyms and use fast reauthentication (default) #eap_sim_id=3 +# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting +# permanent identity when using EAP-SIM/AKA/AKA'. +#imsi_privacy_key=imsi-privacy-key.pem + # 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 @@ -1651,12 +1709,15 @@ own_ip_addr=127.0.0.1 #wpa_psk_file=/etc/hostapd.wpa_psk # Optionally, WPA passphrase can be received from RADIUS authentication server -# This requires macaddr_acl to be set to 2 (RADIUS) +# This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values +# 1 and 2. # 0 = disabled (default) # 1 = optional; use default passphrase/psk if RADIUS server does not include # Tunnel-Password # 2 = required; reject authentication if RADIUS server does not include # Tunnel-Password +# 3 = ask RADIUS server during 4-way handshake if there is no locally +# configured PSK/passphrase for the STA #wpa_psk_radius=0 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 26091211..60396f3d 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1169,7 +1169,7 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, "arguments (count and freq)\n" "usage: [sec_channel_offset=] " "[center_freq1=] [center_freq2=] [bandwidth=] " - "[blocktx] [ht|vht]\n"); + "[blocktx] [ht|vht|he|eht]\n"); return -1; } diff --git a/hostapd/main.c b/hostapd/main.c index d028fb5d..eab57b61 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -15,6 +15,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/uuid.h" +#include "crypto/crypto.h" #include "crypto/random.h" #include "crypto/tls.h" #include "common/version.h" @@ -725,7 +726,6 @@ int main(int argc, char *argv[]) case 'v': show_version(); exit(1); - break; case 'g': if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) return -1; @@ -947,6 +947,7 @@ int main(int argc, char *argv[]) fst_global_deinit(); + crypto_unload(); os_program_deinit(); return ret; diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk index c42d53cf..bb773413 100644 --- a/hs20/client/Android.mk +++ b/hs20/client/Android.mk @@ -60,6 +60,10 @@ L_CFLAGS += -DEAP_TLS_OPENSSL L_CFLAGS += -Wno-unused-parameter +ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0) +L_CFLAGS += -DCONFIG_ANDROID_LOG +L_CFLAGS += -DANDROID_LOG_NAME='"hs20-osu-client"' +endif ######################## include $(CLEAR_VARS) @@ -71,9 +75,15 @@ LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES := libc libcutils LOCAL_SHARED_LIBRARIES += libcrypto libssl +ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0) +LOCAL_VENDOR_MODULE := true +LOCAL_SHARED_LIBRARIES += libxml2 +LOCAL_SHARED_LIBRARIES += liblog +else #LOCAL_SHARED_LIBRARIES += libxml2 LOCAL_STATIC_LIBRARIES += libxml2 LOCAL_SHARED_LIBRARIES += libicuuc +endif # End of check for platform version LOCAL_SHARED_LIBRARIES += libcurl LOCAL_CFLAGS := $(L_CFLAGS) diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c index 11bf0db3..7b274dac 100644 --- a/hs20/client/osu_client.c +++ b/hs20/client/osu_client.c @@ -2911,20 +2911,27 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) int found; char *host = NULL; - wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)", - !ctx->no_osu_cert_validation, ctx->server_url); + wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)", + !ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A", + ctx->server_url); - host = get_hostname(ctx->server_url); + if (ctx->no_osu_cert_validation && cert->url) + host = get_hostname(cert->url); + else + host = get_hostname(ctx->server_url); - for (i = 0; i < ctx->server_dnsname_count; i++) - os_free(ctx->server_dnsname[i]); - os_free(ctx->server_dnsname); - ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *)); - ctx->server_dnsname_count = 0; + if (!ctx->no_osu_cert_validation) { + for (i = 0; i < ctx->server_dnsname_count; i++) + os_free(ctx->server_dnsname[i]); + os_free(ctx->server_dnsname); + ctx->server_dnsname = os_calloc(cert->num_dnsname, + sizeof(char *)); + ctx->server_dnsname_count = 0; + } found = 0; for (i = 0; i < cert->num_dnsname; i++) { - if (ctx->server_dnsname) { + if (!ctx->no_osu_cert_validation && ctx->server_dnsname) { ctx->server_dnsname[ctx->server_dnsname_count] = os_strdup(cert->dnsname[i]); if (ctx->server_dnsname[ctx->server_dnsname_count]) @@ -3249,7 +3256,6 @@ int main(int argc, char *argv[]) default: usage(); exit(0); - break; } } diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c index 39d10e03..194518e5 100644 --- a/hs20/client/spp_client.c +++ b/hs20/client/spp_client.c @@ -564,7 +564,6 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec, free(id); return -1; } - return 0; } if (strcasecmp(name, "uploadMO") == 0) { diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c index a50e9074..72694be6 100644 --- a/hs20/server/spp_server.c +++ b/hs20/server/spp_server.c @@ -1385,8 +1385,11 @@ static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx, SUBSCRIPTION_REGISTRATION, mac_addr) < 0) return NULL; val = db_get_osu_config_val(ctx, realm, "signup_url"); - if (val == NULL) + if (!val) { + hs20_eventlog(ctx, NULL, realm, session_id, + "signup_url not configured in osu_config", NULL); return NULL; + } spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", NULL); diff --git a/src/ap/acs.c b/src/ap/acs.c index 0030edc2..faaedbfd 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -540,6 +540,10 @@ static void acs_survey_mode_interference_factor( if (!acs_usable_chan(chan)) continue; + if ((chan->flag & HOSTAPD_CHAN_RADAR) && + iface->conf->acs_exclude_dfs) + continue; + if (!is_in_chanlist(iface, chan)) continue; @@ -670,6 +674,10 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, if (!chan_pri_allowed(chan)) continue; + if ((chan->flag & HOSTAPD_CHAN_RADAR) && + iface->conf->acs_exclude_dfs) + continue; + if (!is_in_chanlist(iface, chan)) continue; @@ -1044,7 +1052,9 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, for (i = 0; i < mode->num_channels; i++) { chan = &mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) + if ((chan->flag & HOSTAPD_CHAN_DISABLED) || + ((chan->flag & HOSTAPD_CHAN_RADAR) && + iface->conf->acs_exclude_dfs)) continue; if (!is_in_chanlist(iface, chan)) diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 33c68d43..db86a761 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration helper functions - * Copyright (c) 2003-2014, Jouni Malinen + * Copyright (c) 2003-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -463,9 +463,12 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid) wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)", (u8 *) ssid->wpa_passphrase, os_strlen(ssid->wpa_passphrase)); - pbkdf2_sha1(ssid->wpa_passphrase, - ssid->ssid, ssid->ssid_len, - 4096, ssid->wpa_psk->psk, PMK_LEN); + if (pbkdf2_sha1(ssid->wpa_passphrase, + ssid->ssid, ssid->ssid_len, + 4096, ssid->wpa_psk->psk, PMK_LEN) != 0) { + wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()"); + return -1; + } wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)", ssid->wpa_psk->psk, PMK_LEN); return 0; @@ -811,6 +814,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->eap_fast_a_id); os_free(conf->eap_fast_a_id_info); os_free(conf->eap_sim_db); + os_free(conf->imsi_privacy_key); os_free(conf->radius_server_clients); os_free(conf->radius); os_free(conf->radius_das_shared_secret); @@ -1245,15 +1249,18 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, if (full_config && bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED && + bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS && bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no " "RADIUS checking (macaddr_acl=2) enabled."); return -1; } - if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) && + if (full_config && bss->wpa && + wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) && bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL && bss->ssid.wpa_psk_file == NULL && + bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS && (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED || bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) { wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase " @@ -1426,7 +1433,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, #endif /* CONFIG_SAE_PK */ #ifdef CONFIG_FILS - if (full_config && bss->fils_discovery_min_int && + if (full_config && bss->fils_discovery_max_int && bss->unsol_bcast_probe_resp_interval) { wpa_printf(MSG_ERROR, "Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time"); @@ -1434,6 +1441,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211BE + if (full_config && !bss->disable_11be && bss->disable_11ax) { + bss->disable_11be = true; + wpa_printf(MSG_INFO, + "Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS"); + } +#endif /* CONFIG_IEEE80211BE */ + return 0; } @@ -1465,6 +1480,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) { size_t i; + if (full_config && is_6ghz_op_class(conf->op_class) && + !conf->hw_mode_set) { + /* Use the appropriate hw_mode value automatically when the + * op_class parameter has been set, but hw_mode was not. */ + conf->hw_mode = HOSTAPD_MODE_IEEE80211A; + } + if (full_config && conf->ieee80211d && (!conf->country[0] || !conf->country[1])) { wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without " @@ -1502,6 +1524,14 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) return -1; } +#ifdef CONFIG_IEEE80211BE + if (full_config && conf->ieee80211be && !conf->ieee80211ax) { + wpa_printf(MSG_ERROR, + "Cannot set ieee80211be without ieee80211ax"); + return -1; + } +#endif /* CONFIG_IEEE80211BE */ + for (i = 0; i < conf->num_bss; i++) { if (hostapd_config_check_bss(conf->bss[i], conf, full_config)) return -1; @@ -1648,3 +1678,49 @@ bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf) return with_pk; } #endif /* CONFIG_SAE_PK */ + + +int hostapd_acl_comp(const void *a, const void *b) +{ + const struct mac_acl_entry *aa = a; + const struct mac_acl_entry *bb = b; + return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); +} + + +int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, + int vlan_id, const u8 *addr) +{ + struct mac_acl_entry *newacl; + + newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); + if (!newacl) { + wpa_printf(MSG_ERROR, "MAC list reallocation failed"); + return -1; + } + + *acl = newacl; + os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); + os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id)); + (*acl)[*num].vlan_id.untagged = vlan_id; + (*acl)[*num].vlan_id.notempty = !!vlan_id; + (*num)++; + + return 0; +} + + +void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, + const u8 *addr) +{ + int i = 0; + + while (i < *num) { + if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) { + os_remove_in_array(*acl, *num, sizeof(**acl), i); + (*num)--; + } else { + i++; + } + } +} diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index c1a0f718..b97d49c2 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -1,6 +1,6 @@ /* * hostapd / Configuration definitions and helpers functions - * Copyright (c) 2003-2015, Jouni Malinen + * Copyright (c) 2003-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,12 @@ #include "fst/fst.h" #include "vlan.h" +enum macaddr_acl { + ACCEPT_UNLESS_DENIED = 0, + DENY_UNLESS_ACCEPTED = 1, + USE_EXTERNAL_RADIUS_AUTH = 2 +}; + /** * mesh_conf - local MBSS state and settings */ @@ -331,12 +337,11 @@ struct hostapd_bss_config { int eap_reauth_period; int erp_send_reauth_start; char *erp_domain; +#ifdef CONFIG_TESTING_OPTIONS + bool eap_skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ - enum macaddr_acl { - ACCEPT_UNLESS_DENIED = 0, - DENY_UNLESS_ACCEPTED = 1, - USE_EXTERNAL_RADIUS_AUTH = 2 - } macaddr_acl; + enum macaddr_acl macaddr_acl; struct mac_acl_entry *accept_mac; int num_accept_mac; struct mac_acl_entry *deny_mac; @@ -364,7 +369,8 @@ struct hostapd_bss_config { enum { PSK_RADIUS_IGNORED = 0, PSK_RADIUS_ACCEPTED = 1, - PSK_RADIUS_REQUIRED = 2 + PSK_RADIUS_REQUIRED = 2, + PSK_RADIUS_DURING_4WAY_HS = 3, } wpa_psk_radius; int wpa_pairwise; int group_cipher; /* wpa_group value override from configuation */ @@ -439,6 +445,7 @@ struct hostapd_bss_config { int eap_teap_id; int eap_sim_aka_result_ind; int eap_sim_id; + char *imsi_privacy_key; int tnc; int fragment_size; u16 pwd_group; @@ -537,6 +544,7 @@ struct hostapd_bss_config { bool disable_11n; bool disable_11ac; bool disable_11ax; + bool disable_11be; /* IEEE 802.11v */ int time_advertisement; @@ -848,6 +856,13 @@ struct hostapd_bss_config { */ int mka_priority; + /** + * macsec_csindex - Cipher suite index for MACsec + * + * Range: 0-1 (default: 0) + */ + int macsec_csindex; + /** * mka_ckn - MKA pre-shared CKN */ @@ -936,6 +951,15 @@ struct spatial_reuse { u8 srg_partial_bssid_bitmap[8]; }; +/** + * struct eht_phy_capabilities_info - EHT PHY capabilities + */ +struct eht_phy_capabilities_info { + bool su_beamformer; + bool su_beamformee; + bool mu_beamformer; +}; + /** * struct hostapd_config - Per-radio interface configuration */ @@ -957,7 +981,9 @@ struct hostapd_config { int acs_exclude_dfs; u8 min_tx_power; enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ + bool hw_mode_set; int acs_exclude_6ghz_non_psc; + int enable_background_radar; enum { LONG_PREAMBLE = 0, SHORT_PREAMBLE = 1 @@ -1075,6 +1101,7 @@ struct hostapd_config { u8 he_6ghz_max_ampdu_len_exp; u8 he_6ghz_rx_ant_pat; u8 he_6ghz_tx_ant_pat; + u8 he_6ghz_reg_pwr_type; #endif /* CONFIG_IEEE80211AX */ /* VHT enable/disable config from CHAN_SWITCH */ @@ -1102,11 +1129,27 @@ struct hostapd_config { unsigned int airtime_update_interval; #define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1) #endif /* CONFIG_AIRTIME_POLICY */ + + int ieee80211be; +#ifdef CONFIG_IEEE80211BE + u8 eht_oper_chwidth; + u8 eht_oper_centr_freq_seg0_idx; + struct eht_phy_capabilities_info eht_phy_capab; +#endif /* CONFIG_IEEE80211BE */ + + /* EHT enable/disable config from CHAN_SWITCH */ +#define CH_SWITCH_EHT_ENABLED BIT(0) +#define CH_SWITCH_EHT_DISABLED BIT(1) + unsigned int ch_switch_eht_config; }; static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + return conf->eht_oper_chwidth; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) return conf->he_oper_chwidth; @@ -1117,6 +1160,10 @@ static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf) static inline void hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + conf->eht_oper_chwidth = oper_chwidth; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) conf->he_oper_chwidth = oper_chwidth; @@ -1127,6 +1174,10 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth) static inline u8 hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + return conf->eht_oper_centr_freq_seg0_idx; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) return conf->he_oper_centr_freq_seg0_idx; @@ -1138,6 +1189,10 @@ static inline void hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf, u8 oper_centr_freq_seg0_idx) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx; @@ -1197,5 +1252,10 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf); bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf); bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf); int hostapd_setup_sae_pt(struct hostapd_bss_config *conf); +int hostapd_acl_comp(const void *a, const void *b); +int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, + int vlan_id, const u8 *addr); +void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, + const u8 *addr); #endif /* HOSTAPD_CONFIG_H */ diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index e9177366..8af7a0e2 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -418,6 +418,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, const struct ieee80211_vht_capabilities *vht_capab, const struct ieee80211_he_capabilities *he_capab, size_t he_capab_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set) @@ -440,6 +442,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.vht_capabilities = vht_capab; params.he_capab = he_capab; params.he_capab_len = he_capab_len; + params.eht_capab = eht_capab; + params.eht_capab_len = eht_capab_len; params.he_6ghz_capab = he_6ghz_capab; params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED); params.vht_opmode = vht_opmode; @@ -547,7 +551,7 @@ 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 edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, - int he_enabled, + int he_enabled, bool eht_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1) { @@ -556,12 +560,15 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, if (hostapd_set_freq_params(&data, mode, freq, channel, edmg, edmg_channel, ht_enabled, - vht_enabled, he_enabled, sec_channel_offset, - oper_chwidth, + vht_enabled, he_enabled, eht_enabled, + sec_channel_offset, oper_chwidth, center_segment0, center_segment1, cmode ? cmode->vht_capab : 0, cmode ? - &cmode->he_capab[IEEE80211_MODE_AP] : NULL)) + &cmode->he_capab[IEEE80211_MODE_AP] : NULL, + cmode ? + &cmode->eht_capab[IEEE80211_MODE_AP] : + NULL)) return -1; if (hapd->driver == NULL) @@ -810,9 +817,10 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd, int hostapd_start_dfs_cac(struct hostapd_iface *iface, enum hostapd_hw_mode mode, int freq, int channel, int ht_enabled, int vht_enabled, - int he_enabled, + int he_enabled, bool eht_enabled, int sec_channel_offset, int oper_chwidth, - int center_segment0, int center_segment1) + int center_segment0, int center_segment1, + bool radar_background) { struct hostapd_data *hapd = iface->bss[0]; struct hostapd_freq_params data; @@ -830,18 +838,24 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0, ht_enabled, - vht_enabled, he_enabled, sec_channel_offset, + vht_enabled, he_enabled, eht_enabled, + sec_channel_offset, oper_chwidth, center_segment0, center_segment1, cmode->vht_capab, - &cmode->he_capab[IEEE80211_MODE_AP])) { + &cmode->he_capab[IEEE80211_MODE_AP], + &cmode->eht_capab[IEEE80211_MODE_AP])) { wpa_printf(MSG_ERROR, "Can't set freq params"); return -1; } + data.radar_background = radar_background; res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data); if (!res) { - iface->cac_started = 1; + if (radar_background) + iface->radar_background.cac_started = 1; + else + iface->cac_started = 1; os_get_reltime(&iface->dfs_cac_start); } @@ -953,13 +967,15 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) params.ht40_enabled = !!(hapd->iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET); params.vht_enabled = !!(hapd->iface->conf->ieee80211ac); + params.eht_enabled = !!(hapd->iface->conf->ieee80211be); params.ch_width = 20; if (hapd->iface->conf->ieee80211n && params.ht40_enabled) params.ch_width = 40; /* Note: VHT20 is defined by combination of ht_capab & oper_chwidth */ - if ((hapd->iface->conf->ieee80211ax || + if ((hapd->iface->conf->ieee80211be || + hapd->iface->conf->ieee80211ax || hapd->iface->conf->ieee80211ac) && params.ht40_enabled) { u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf); diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 61c8f64e..b4fb766e 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -43,6 +43,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, const struct ieee80211_vht_capabilities *vht_capab, const struct ieee80211_he_capabilities *he_capab, size_t he_capab_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set); @@ -64,8 +66,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, 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 edmg, u8 edmg_channel, - int ht_enabled, int vht_enabled, - int he_enabled, int sec_channel_offset, int oper_chwidth, + int ht_enabled, int vht_enabled, int he_enabled, + bool eht_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1); int hostapd_set_rts(struct hostapd_data *hapd, int rts); int hostapd_set_frag(struct hostapd_data *hapd, int frag); @@ -128,9 +130,10 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, int hostapd_start_dfs_cac(struct hostapd_iface *iface, enum hostapd_hw_mode mode, int freq, int channel, int ht_enabled, int vht_enabled, - int he_enabled, + int he_enabled, bool eht_enabled, int sec_channel_offset, int oper_chwidth, - int center_segment0, int center_segment1); + int center_segment0, int center_segment1, + bool radar_background); int hostapd_drv_do_acs(struct hostapd_data *hapd); int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer, u16 reason_code, const u8 *ie, size_t ielen); @@ -299,6 +302,17 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, return hapd->driver->switch_channel(hapd->drv_priv, settings); } +#ifdef CONFIG_IEEE80211AX +static inline int hostapd_drv_switch_color(struct hostapd_data *hapd, + struct cca_settings *settings) +{ + if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv) + return -1; + + return hapd->driver->switch_color(hapd->drv_priv, settings); +} +#endif /* CONFIG_IEEE80211AX */ + static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, size_t buflen) { diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 8e12daf4..fd9c96fa 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "crypto/crypto.h" #include "crypto/tls.h" #include "eap_server/eap.h" #include "eap_server/eap_sim_db.h" @@ -168,6 +169,9 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev, wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s", data->alert.description); break; + case TLS_UNSAFE_RENEGOTIATION_DISABLED: + /* Not applicable to TLS server */ + break; } } #endif /* EAP_TLS_FUNCS */ @@ -209,6 +213,7 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) 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->imsi_privacy_key = hapd->imsi_privacy_key; cfg->tnc = hapd->conf->tnc; cfg->wps = hapd->wps; cfg->fragment_size = hapd->conf->fragment_size; @@ -222,6 +227,9 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) cfg->server_id_len = 7; } cfg->erp = hapd->conf->eap_server_erp; +#ifdef CONFIG_TESTING_OPTIONS + cfg->skip_prot_success = hapd->conf->eap_skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ return cfg; } @@ -292,6 +300,22 @@ int authsrv_init(struct hostapd_data *hapd) } #endif /* EAP_TLS_FUNCS */ +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(hapd->imsi_privacy_key); + hapd->imsi_privacy_key = NULL; + if (hapd->conf->imsi_privacy_key) { + hapd->imsi_privacy_key = crypto_rsa_key_read( + hapd->conf->imsi_privacy_key, true); + if (!hapd->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "Failed to read/parse IMSI privacy key %s", + hapd->conf->imsi_privacy_key); + authsrv_deinit(hapd); + return -1; + } + } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + #ifdef EAP_SIM_DB if (hapd->conf->eap_sim_db) { hapd->eap_sim_db_priv = @@ -332,6 +356,11 @@ void authsrv_deinit(struct hostapd_data *hapd) hapd->radius_srv = NULL; #endif /* RADIUS_SERVER */ +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(hapd->imsi_privacy_key); + hapd->imsi_privacy_key = NULL; +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + #ifdef EAP_TLS_FUNCS if (hapd->ssl_ctx) { tls_deinit(hapd->ssl_ctx); diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 8cd1c417..eaa40332 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -186,7 +186,8 @@ static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) } -static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, +static u8 * hostapd_eid_country_add(struct hostapd_data *hapd, u8 *pos, + u8 *end, int chan_spacing, struct hostapd_channel_data *start, struct hostapd_channel_data *prev) { @@ -198,31 +199,23 @@ static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, /* number of channels */ *pos++ = (prev->chan - start->chan) / chan_spacing + 1; /* maximum transmit power level */ - *pos++ = start->max_tx_power; + if (!is_6ghz_op_class(hapd->iconf->op_class)) + *pos++ = start->max_tx_power; + else + *pos++ = 0; /* Reserved when operating on the 6 GHz band */ return pos; } -static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, - int max_len) +static u8 * hostapd_fill_subband_triplets(struct hostapd_data *hapd, u8 *pos, + u8 *end) { - u8 *pos = eid; - u8 *end = eid + max_len; int i; struct hostapd_hw_modes *mode; struct hostapd_channel_data *start, *prev; int chan_spacing = 1; - if (!hapd->iconf->ieee80211d || max_len < 6 || - hapd->iface->current_mode == NULL) - return eid; - - *pos++ = WLAN_EID_COUNTRY; - pos++; /* length will be set later */ - os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ - pos += 3; - mode = hapd->iface->current_mode; if (mode->mode == HOSTAPD_MODE_IEEE80211A) chan_spacing = 4; @@ -240,7 +233,8 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, } if (start && prev) { - pos = hostapd_eid_country_add(pos, end, chan_spacing, + pos = hostapd_eid_country_add(hapd, pos, end, + chan_spacing, start, prev); start = NULL; } @@ -250,10 +244,50 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, } if (start) { - pos = hostapd_eid_country_add(pos, end, chan_spacing, + pos = hostapd_eid_country_add(hapd, pos, end, chan_spacing, start, prev); } + return pos; +} + + +static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, + int max_len) +{ + u8 *pos = eid; + u8 *end = eid + max_len; + + if (!hapd->iconf->ieee80211d || max_len < 6 || + hapd->iface->current_mode == NULL) + return eid; + + *pos++ = WLAN_EID_COUNTRY; + pos++; /* length will be set later */ + os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ + pos += 3; + + if (is_6ghz_op_class(hapd->iconf->op_class)) { + /* Force the third octet of the country string to indicate + * Global Operating Class (Table E-4) */ + eid[4] = 0x04; + + /* Operating Triplet field */ + /* Operating Extension Identifier (>= 201 to indicate this is + * not a Subband Triplet field) */ + *pos++ = 201; + /* Operating Class */ + *pos++ = hapd->iconf->op_class; + /* Coverage Class */ + *pos++ = 0; + /* Subband Triplets are required only for the 20 MHz case */ + if (hapd->iconf->op_class == 131 || + hapd->iconf->op_class == 136) + pos = hostapd_fill_subband_triplets(hapd, pos, end); + } else { + pos = hostapd_fill_subband_triplets(hapd, pos, end); + } + if ((pos - eid) & 1) { if (end - pos < 1) return eid; @@ -463,12 +497,25 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, 3 + sizeof(struct ieee80211_he_operation) + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + 3 + sizeof(struct ieee80211_spatial_reuse); - if (is_6ghz_op_class(hapd->iconf->op_class)) + if (is_6ghz_op_class(hapd->iconf->op_class)) { buflen += sizeof(struct ieee80211_he_6ghz_oper_info) + 3 + sizeof(struct ieee80211_he_6ghz_band_cap); + /* An additional Transmit Power Envelope element for + * subordinate client */ + if (hapd->iconf->he_6ghz_reg_pwr_type == + HE_6GHZ_INDOOR_AP) + buflen += 4; + } } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP); + buflen += 3 + sizeof(struct ieee80211_eht_operation); + } +#endif /* CONFIG_IEEE80211BE */ + buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd); @@ -578,14 +625,30 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { + u8 *cca_pos; + pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP); pos = hostapd_eid_he_operation(hapd, pos); + + /* BSS Color Change Announcement element */ + cca_pos = hostapd_eid_cca(hapd, pos); + if (cca_pos != pos) + hapd->cca_c_off_proberesp = cca_pos - (u8 *) resp - 2; + pos = cca_pos; + pos = hostapd_eid_spatial_reuse(hapd, pos); pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos); pos = hostapd_eid_he_6ghz_band_cap(hapd, pos); } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP); + pos = hostapd_eid_eht_operation(hapd, pos); + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AC if (hapd->conf->vendor_vht) pos = hostapd_eid_vendor_vht(hapd, pos); @@ -1319,6 +1382,15 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) buf_len = pos - buf; total_len += buf_len; +#ifdef CONFIG_IEEE80211AX + /* Transmit Power Envelope element(s) */ + if (is_6ghz_op_class(hapd->iconf->op_class)) { + total_len += 4; + if (hapd->iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) + total_len += 4; + } +#endif /* CONFIG_IEEE80211AX */ + head = os_zalloc(total_len); if (!head) return NULL; @@ -1391,6 +1463,9 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) pos += buf_len; } + if (is_6ghz_op_class(hapd->iconf->op_class)) + pos = hostapd_eid_txpower_envelope(hapd, pos); + *len = pos - (u8 *) head; wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template", head, pos - (u8 *) head); @@ -1465,12 +1540,25 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, 3 + sizeof(struct ieee80211_he_operation) + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + 3 + sizeof(struct ieee80211_spatial_reuse); - if (is_6ghz_op_class(hapd->iconf->op_class)) + if (is_6ghz_op_class(hapd->iconf->op_class)) { tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) + 3 + sizeof(struct ieee80211_he_6ghz_band_cap); + /* An additional Transmit Power Envelope element for + * subordinate client */ + if (hapd->iconf->he_6ghz_reg_pwr_type == + HE_6GHZ_INDOOR_AP) + tail_len += 4; + } } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP); + tail_len += 3 + sizeof(struct ieee80211_eht_operation); + } +#endif /* CONFIG_IEEE80211BE */ + tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON); tail_len += hostapd_mbo_ie_len(hapd); tail_len += hostapd_eid_owe_trans_len(hapd); @@ -1600,15 +1688,32 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { + u8 *cca_pos; + tailpos = hostapd_eid_he_capab(hapd, tailpos, IEEE80211_MODE_AP); tailpos = hostapd_eid_he_operation(hapd, tailpos); + + /* BSS Color Change Announcement element */ + cca_pos = hostapd_eid_cca(hapd, tailpos); + if (cca_pos != tailpos) + hapd->cca_c_off_beacon = cca_pos - tail - 2; + tailpos = cca_pos; + tailpos = hostapd_eid_spatial_reuse(hapd, tailpos); tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos); tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos); } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + tailpos = hostapd_eid_eht_capab(hapd, tailpos, + IEEE80211_MODE_AP); + tailpos = hostapd_eid_eht_operation(hapd, tailpos); + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AC if (hapd->conf->vendor_vht) tailpos = hostapd_eid_vendor_vht(hapd, tailpos); @@ -1845,12 +1950,14 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd) iconf->channel, iconf->enable_edmg, iconf->edmg_channel, iconf->ieee80211n, iconf->ieee80211ac, iconf->ieee80211ax, + iconf->ieee80211be, iconf->secondary_channel, hostapd_get_oper_chwidth(iconf), hostapd_get_oper_centr_freq_seg0_idx(iconf), hostapd_get_oper_centr_freq_seg1_idx(iconf), cmode->vht_capab, - &cmode->he_capab[IEEE80211_MODE_AP]) == 0) + &cmode->he_capab[IEEE80211_MODE_AP], + &cmode->eht_capab[IEEE80211_MODE_AP]) == 0) params.freq = &freq; res = hostapd_drv_set_ap(hapd, ¶ms); diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 1d8fb824..29b41f5b 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -24,6 +24,7 @@ #include "ap_drv_ops.h" #include "mbo_ap.h" #include "taxonomy.h" +#include "wnm_ap.h" static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen, @@ -724,15 +725,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, } else { /* CAC started and CAC time set - calculate remaining time */ struct os_reltime now; - unsigned int left_time; + long left_time; os_reltime_age(&iface->dfs_cac_start, &now); - left_time = iface->dfs_cac_ms / 1000 - now.sec; + left_time = (long) iface->dfs_cac_ms / 1000 - now.sec; ret = os_snprintf(buf + len, buflen - len, "cac_time_seconds=%u\n" - "cac_time_left_seconds=%u\n", + "cac_time_left_seconds=%lu\n", iface->dfs_cac_ms / 1000, - left_time); + left_time > 0 ? left_time : 0); } if (os_snprintf_error(buflen - len, ret)) return len; @@ -746,6 +747,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, "ieee80211n=%d\n" "ieee80211ac=%d\n" "ieee80211ax=%d\n" + "ieee80211be=%d\n" "beacon_int=%u\n" "dtim_period=%d\n", iface->conf->channel, @@ -758,12 +760,27 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, !hapd->conf->disable_11ac, iface->conf->ieee80211ax && !hapd->conf->disable_11ax, + iface->conf->ieee80211be && + !hapd->conf->disable_11be, iface->conf->beacon_int, hapd->conf->dtim_period); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; +#ifdef CONFIG_IEEE80211BE + if (iface->conf->ieee80211be && !hapd->conf->disable_11be) { + ret = os_snprintf(buf + len, buflen - len, + "eht_oper_chwidth=%d\n" + "eht_oper_centr_freq_seg0_idx=%d\n", + iface->conf->eht_oper_chwidth, + iface->conf->eht_oper_centr_freq_seg0_idx); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AX if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) { ret = os_snprintf(buf + len, buflen - len, @@ -918,6 +935,7 @@ int hostapd_parse_csa_settings(const char *pos, settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); settings->freq_params.he_enabled = !!os_strstr(pos, " he"); + settings->freq_params.eht_enabled = !!os_strstr(pos, " eht"); settings->block_tx = !!os_strstr(pos, " blocktx"); #undef SET_CSA_SETTING @@ -1047,3 +1065,351 @@ void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd) #endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + +#ifdef CONFIG_WNM_AP + +int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + int disassoc_timer; + struct sta_info *sta; + + if (hwaddr_aton(cmd, addr)) + return -1; + if (cmd[17] != ' ') + return -1; + disassoc_timer = atoi(cmd + 17); + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for disassociation imminent message", + MAC2STR(addr)); + return -1; + } + + return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); +} + + +int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + const char *url, *timerstr; + int disassoc_timer; + struct sta_info *sta; + + if (hwaddr_aton(cmd, addr)) + return -1; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for ESS disassociation imminent message", + MAC2STR(addr)); + return -1; + } + + timerstr = cmd + 17; + if (*timerstr != ' ') + return -1; + timerstr++; + disassoc_timer = atoi(timerstr); + if (disassoc_timer < 0 || disassoc_timer > 65535) + return -1; + + url = os_strchr(timerstr, ' '); + if (url == NULL) + return -1; + url++; + + return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); +} + + +int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + const char *pos, *end; + int disassoc_timer = 0; + struct sta_info *sta; + u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01; + u8 bss_term_dur[12]; + char *url = NULL; + int ret; + u8 nei_rep[1000]; + int nei_len; + u8 mbo[10]; + size_t mbo_len = 0; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for BSS TM Request message", + MAC2STR(addr)); + return -1; + } + + pos = os_strstr(cmd, " disassoc_timer="); + if (pos) { + pos += 16; + disassoc_timer = atoi(pos); + if (disassoc_timer < 0 || disassoc_timer > 65535) { + wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); + return -1; + } + } + + pos = os_strstr(cmd, " valid_int="); + if (pos) { + pos += 11; + valid_int = atoi(pos); + } + + pos = os_strstr(cmd, " dialog_token="); + if (pos) { + pos += 14; + dialog_token = atoi(pos); + } + + pos = os_strstr(cmd, " bss_term="); + if (pos) { + pos += 10; + req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; + /* TODO: TSF configurable/learnable */ + bss_term_dur[0] = 4; /* Subelement ID */ + bss_term_dur[1] = 10; /* Length */ + os_memset(&bss_term_dur[2], 0, 8); + end = os_strchr(pos, ','); + if (end == NULL) { + wpa_printf(MSG_DEBUG, "Invalid bss_term data"); + return -1; + } + end++; + WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); + } + + nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep, + sizeof(nei_rep)); + if (nei_len < 0) + return -1; + + pos = os_strstr(cmd, " url="); + if (pos) { + size_t len; + pos += 5; + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + url = os_malloc(len + 1); + if (url == NULL) + return -1; + os_memcpy(url, pos, len); + url[len] = '\0'; + req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; + } + + if (os_strstr(cmd, " pref=1")) + req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; + if (os_strstr(cmd, " abridged=1")) + req_mode |= WNM_BSS_TM_REQ_ABRIDGED; + if (os_strstr(cmd, " disassoc_imminent=1")) + req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; + +#ifdef CONFIG_MBO + pos = os_strstr(cmd, "mbo="); + if (pos) { + unsigned int mbo_reason, cell_pref, reassoc_delay; + u8 *mbo_pos = mbo; + + ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason, + &reassoc_delay, &cell_pref); + if (ret != 3) { + wpa_printf(MSG_DEBUG, + "MBO requires three arguments: mbo=::"); + ret = -1; + goto fail; + } + + if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) { + wpa_printf(MSG_DEBUG, + "Invalid MBO transition reason code %u", + mbo_reason); + ret = -1; + goto fail; + } + + /* Valid values for Cellular preference are: 0, 1, 255 */ + if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) { + wpa_printf(MSG_DEBUG, + "Invalid MBO cellular capability %u", + cell_pref); + ret = -1; + goto fail; + } + + if (reassoc_delay > 65535 || + (reassoc_delay && + !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) { + wpa_printf(MSG_DEBUG, + "MBO: Assoc retry delay is only valid in disassoc imminent mode"); + ret = -1; + goto fail; + } + + *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON; + *mbo_pos++ = 1; + *mbo_pos++ = mbo_reason; + *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF; + *mbo_pos++ = 1; + *mbo_pos++ = cell_pref; + + if (reassoc_delay) { + *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY; + *mbo_pos++ = 2; + WPA_PUT_LE16(mbo_pos, reassoc_delay); + mbo_pos += 2; + } + + mbo_len = mbo_pos - mbo; + } +#endif /* CONFIG_MBO */ + + ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, + valid_int, bss_term_dur, dialog_token, url, + nei_len ? nei_rep : NULL, nei_len, + mbo_len ? mbo : NULL, mbo_len); +#ifdef CONFIG_MBO +fail: +#endif /* CONFIG_MBO */ + os_free(url); + return ret; +} + +#endif /* CONFIG_WNM_AP */ + + +int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, + const char *txtaddr) +{ + u8 addr[ETH_ALEN]; + struct vlan_description vlan_id; + + if (!(*num)) + return 0; + + if (hwaddr_aton(txtaddr, addr)) + return -1; + + if (hostapd_maclist_found(*acl, *num, addr, &vlan_id)) + hostapd_remove_acl_mac(acl, num, addr); + + return 0; +} + + +void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, + int *num) +{ + while (*num) + hostapd_remove_acl_mac(acl, num, (*acl)[0].addr); +} + + +int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, + char *buf, size_t buflen) +{ + int i = 0, len = 0, ret = 0; + + if (!acl) + return 0; + + while (i < num) { + ret = os_snprintf(buf + len, buflen - len, + MACSTR " VLAN_ID=%d\n", + MAC2STR(acl[i].addr), + acl[i].vlan_id.untagged); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + i++; + len += ret; + } + return len; +} + + +int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + struct vlan_description vlan_id; + int ret = 0, vlanid = 0; + const char *pos; + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = os_strstr(cmd, "VLAN_ID="); + if (pos) + vlanid = atoi(pos + 8); + + if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) { + ret = hostapd_add_acl_maclist(acl, num, vlanid, addr); + if (ret != -1 && *acl) + qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); + } + + return ret < 0 ? -1 : 0; +} + + +int hostapd_disassoc_accept_mac(struct hostapd_data *hapd) +{ + struct sta_info *sta; + struct vlan_description vlan_id; + + if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED) + return 0; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (!hostapd_maclist_found(hapd->conf->accept_mac, + hapd->conf->num_accept_mac, + sta->addr, &vlan_id) || + (vlan_id.notempty && + vlan_compare(&vlan_id, sta->vlan_desc))) + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } + + return 0; +} + + +int hostapd_disassoc_deny_mac(struct hostapd_data *hapd) +{ + struct sta_info *sta; + struct vlan_description vlan_id; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (hostapd_maclist_found(hapd->conf->deny_mac, + hapd->conf->num_deny_mac, sta->addr, + &vlan_id) && + (!vlan_id.notempty || + !vlan_compare(&vlan_id, sta->vlan_desc))) + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } + + return 0; +} diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h index d1dcebfb..614f0426 100644 --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -37,4 +37,21 @@ int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd, const u8 *addr, char *buf, size_t len); void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd); +int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, + const char *cmd); +int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, + const char *cmd); +int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, + const char *cmd); +int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, + const char *cmd); +int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, + const char *txtaddr); +void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, + int *num); +int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, + char *buf, size_t buflen); +int hostapd_disassoc_accept_mac(struct hostapd_data *hapd); +int hostapd_disassoc_deny_mac(struct hostapd_data *hapd); + #endif /* CTRL_IFACE_AP_H */ diff --git a/src/ap/dfs.c b/src/ap/dfs.c index 5c99ecfd..e46dd7ed 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -19,6 +19,26 @@ #include "dfs.h" +enum dfs_channel_type { + DFS_ANY_CHANNEL, + DFS_AVAILABLE, /* non-radar or radar-available */ + DFS_NO_CAC_YET, /* radar-not-yet-available */ +}; + +static struct hostapd_channel_data * +dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, + u8 *oper_centr_freq_seg0_idx, + u8 *oper_centr_freq_seg1_idx, + enum dfs_channel_type *channel_type); + + +static bool dfs_use_radar_background(struct hostapd_iface *iface) +{ + return (iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) && + iface->conf->enable_background_radar; +} + + static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) { int n_chans = 1; @@ -51,15 +71,27 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) } +/* dfs_channel_available: select new channel according to type parameter */ static int dfs_channel_available(struct hostapd_channel_data *chan, - int skip_radar) + enum dfs_channel_type type) { + if (type == DFS_NO_CAC_YET) { + /* Select only radar channel where CAC has not been + * performed yet + */ + if ((chan->flag & HOSTAPD_CHAN_RADAR) && + (chan->flag & HOSTAPD_CHAN_DFS_MASK) == + HOSTAPD_CHAN_DFS_USABLE) + return 1; + return 0; + } + /* * When radar detection happens, CSA is performed. However, there's no * time for CAC, so radar channels must be skipped when finding a new * channel for CSA, unless they are available for immediate use. */ - if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) && + if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) && ((chan->flag & HOSTAPD_CHAN_DFS_MASK) != HOSTAPD_CHAN_DFS_AVAILABLE)) return 0; @@ -138,7 +170,7 @@ dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx) static int dfs_chan_range_available(struct hostapd_hw_modes *mode, int first_chan_idx, int num_chans, - int skip_radar) + enum dfs_channel_type type) { struct hostapd_channel_data *first_chan, *chan; int i; @@ -177,7 +209,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode, return 0; } - if (!dfs_channel_available(chan, skip_radar)) { + if (!dfs_channel_available(chan, type)) { wpa_printf(MSG_DEBUG, "DFS: channel not available %d", first_chan->freq + i * 20); return 0; @@ -207,7 +239,7 @@ static int is_in_chanlist(struct hostapd_iface *iface, */ static int dfs_find_channel(struct hostapd_iface *iface, struct hostapd_channel_data **ret_chan, - int idx, int skip_radar) + int idx, enum dfs_channel_type type) { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan; @@ -232,7 +264,7 @@ static int dfs_find_channel(struct hostapd_iface *iface, } /* Skip incompatible chandefs */ - if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) { + if (!dfs_chan_range_available(mode, i, n_chans, type)) { wpa_printf(MSG_DEBUG, "DFS: range not available for %d (%d)", chan->freq, chan->chan); @@ -475,7 +507,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, int *secondary_channel, u8 *oper_centr_freq_seg0_idx, u8 *oper_centr_freq_seg1_idx, - int skip_radar) + enum dfs_channel_type type) { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan = NULL; @@ -499,7 +531,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, return NULL; /* Get the count first */ - num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); + num_available_chandefs = dfs_find_channel(iface, NULL, 0, type); wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d", num_available_chandefs); if (num_available_chandefs == 0) @@ -508,7 +540,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) return NULL; chan_idx = _rand % num_available_chandefs; - dfs_find_channel(iface, &chan, chan_idx, skip_radar); + dfs_find_channel(iface, &chan, chan_idx, type); if (!chan) { wpa_printf(MSG_DEBUG, "DFS: no random channel found"); return NULL; @@ -537,7 +569,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, for (i = 0; i < num_available_chandefs - 1; i++) { /* start from chan_idx + 1, end when chan_idx - 1 */ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs; - dfs_find_channel(iface, &chan2, chan_idx2, skip_radar); + dfs_find_channel(iface, &chan2, chan_idx2, type); if (chan2 && abs(chan2->chan - chan->chan) > 12) { /* two channels are not adjacent */ sec_chan_idx_80p80 = chan2->chan; @@ -568,6 +600,30 @@ dfs_get_valid_channel(struct hostapd_iface *iface, } +static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar) +{ + struct hostapd_channel_data *channel; + u8 cf1 = 0, cf2 = 0; + int sec = 0; + + channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, + skip_radar ? DFS_AVAILABLE : + DFS_ANY_CHANNEL); + if (!channel) { + wpa_printf(MSG_ERROR, "could not get valid channel"); + return -1; + } + + iface->freq = channel->freq; + iface->conf->channel = channel->chan; + iface->conf->secondary_channel = sec; + hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1); + hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2); + + return 0; +} + + static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) { struct hostapd_hw_modes *mode; @@ -755,7 +811,6 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface, */ int hostapd_handle_dfs(struct hostapd_iface *iface) { - struct hostapd_channel_data *channel; int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1; int skip_radar = 0; @@ -810,28 +865,17 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", res, res ? "yes": "no"); if (res) { - int sec = 0; - u8 cf1 = 0, cf2 = 0; - - channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, - skip_radar); - if (!channel) { - wpa_printf(MSG_ERROR, "could not get valid channel"); + if (dfs_set_valid_channel(iface, skip_radar) < 0) { hostapd_set_state(iface, HAPD_IFACE_DFS); return 0; } - - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = sec; - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1); - hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2); } } while (res); /* Finally start CAC */ hostapd_set_state(iface, HAPD_IFACE_DFS); - wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); + wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq, + dfs_use_radar_background(iface) ? " (background)" : ""); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", iface->freq, @@ -844,17 +888,41 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) res = hostapd_start_dfs_cac( iface, iface->conf->hw_mode, iface->freq, iface->conf->channel, iface->conf->ieee80211n, iface->conf->ieee80211ac, - iface->conf->ieee80211ax, + iface->conf->ieee80211ax, iface->conf->ieee80211be, iface->conf->secondary_channel, hostapd_get_oper_chwidth(iface->conf), hostapd_get_oper_centr_freq_seg0_idx(iface->conf), - hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); + hostapd_get_oper_centr_freq_seg1_idx(iface->conf), + dfs_use_radar_background(iface)); if (res) { wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); return -1; } + if (dfs_use_radar_background(iface)) { + /* Cache background radar parameters. */ + iface->radar_background.channel = iface->conf->channel; + iface->radar_background.secondary_channel = + iface->conf->secondary_channel; + iface->radar_background.freq = iface->freq; + iface->radar_background.centr_freq_seg0_idx = + hostapd_get_oper_centr_freq_seg0_idx(iface->conf); + iface->radar_background.centr_freq_seg1_idx = + hostapd_get_oper_centr_freq_seg1_idx(iface->conf); + + /* + * Let's select a random channel according to the + * regulations and perform CAC on dedicated radar chain. + */ + res = dfs_set_valid_channel(iface, 1); + if (res < 0) + return res; + + iface->radar_background.temp_ch = 1; + return 1; + } + return 0; } @@ -876,6 +944,177 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) } +static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface, + int channel, int freq, + int secondary_channel, + u8 current_vht_oper_chwidth, + u8 oper_centr_freq_seg0_idx, + u8 oper_centr_freq_seg1_idx) +{ + struct hostapd_hw_modes *cmode = iface->current_mode; + int ieee80211_mode = IEEE80211_MODE_AP, err; + struct csa_settings csa_settings; + u8 new_vht_oper_chwidth; + unsigned int i; + + wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel); + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL + "freq=%d chan=%d sec_chan=%d", freq, channel, + secondary_channel); + + new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); + hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth); + + /* Setup CSA request */ + os_memset(&csa_settings, 0, sizeof(csa_settings)); + csa_settings.cs_count = 5; + csa_settings.block_tx = 1; +#ifdef CONFIG_MESH + if (iface->mconf) + ieee80211_mode = IEEE80211_MODE_MESH; +#endif /* CONFIG_MESH */ + err = hostapd_set_freq_params(&csa_settings.freq_params, + iface->conf->hw_mode, + freq, channel, + iface->conf->enable_edmg, + iface->conf->edmg_channel, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + iface->conf->ieee80211be, + secondary_channel, + new_vht_oper_chwidth, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, + cmode->vht_capab, + &cmode->he_capab[ieee80211_mode], + &cmode->eht_capab[ieee80211_mode]); + + if (err) { + wpa_printf(MSG_ERROR, + "DFS failed to calculate CSA freq params"); + hostapd_disable_iface(iface); + return err; + } + + for (i = 0; i < iface->num_bss; i++) { + err = hostapd_switch_channel(iface->bss[i], &csa_settings); + if (err) + break; + } + + if (err) { + wpa_printf(MSG_WARNING, + "DFS failed to schedule CSA (%d) - trying fallback", + err); + iface->freq = freq; + iface->conf->channel = channel; + iface->conf->secondary_channel = secondary_channel; + hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth); + hostapd_set_oper_centr_freq_seg0_idx(iface->conf, + oper_centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx(iface->conf, + oper_centr_freq_seg1_idx); + + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); + + return 0; + } + + /* Channel configuration will be updated once CSA completes and + * ch_switch_notify event is received */ + wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); + + return 0; +} + + +static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface) +{ + int sec = 0; + enum dfs_channel_type channel_type = DFS_NO_CAC_YET; + struct hostapd_channel_data *channel; + u8 oper_centr_freq_seg0_idx = 0; + u8 oper_centr_freq_seg1_idx = 0; + + /* + * Allow selection of DFS channel in ETSI to comply with + * uniform spreading. + */ + if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) + channel_type = DFS_ANY_CHANNEL; + + channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + channel_type); + if (!channel || + channel->chan == iface->conf->channel || + channel->chan == iface->radar_background.channel) + channel = dfs_downgrade_bandwidth(iface, &sec, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &channel_type); + if (!channel || + hostapd_start_dfs_cac(iface, iface->conf->hw_mode, + channel->freq, channel->chan, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + iface->conf->ieee80211be, + sec, hostapd_get_oper_chwidth(iface->conf), + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, true)) { + wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel"); + iface->radar_background.channel = -1; + return; + } + + iface->radar_background.channel = channel->chan; + iface->radar_background.freq = channel->freq; + iface->radar_background.secondary_channel = sec; + iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx; + iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx; + + wpa_printf(MSG_DEBUG, + "%s: setting background chain to chan %d (%d MHz)", + __func__, channel->chan, channel->freq); +} + + +static bool +hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq) +{ + return dfs_use_radar_background(iface) && + iface->radar_background.channel != -1 && + iface->radar_background.freq == freq; +} + + +static int +hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface) +{ + u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); + + iface->conf->channel = iface->radar_background.channel; + iface->freq = iface->radar_background.freq; + iface->conf->secondary_channel = + iface->radar_background.secondary_channel; + hostapd_set_oper_centr_freq_seg0_idx( + iface->conf, iface->radar_background.centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx( + iface->conf, iface->radar_background.centr_freq_seg1_idx); + + hostpad_dfs_update_background_chain(iface); + + return hostapd_dfs_request_channel_switch( + iface, iface->conf->channel, iface->freq, + iface->conf->secondary_channel, current_vht_oper_chwidth, + hostapd_get_oper_centr_freq_seg0_idx(iface->conf), + hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); +} + + int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) @@ -896,6 +1135,22 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_AVAILABLE); + + /* + * Radar event from background chain for the selected + * channel. Perform CSA, move the main chain to the + * selected channel and configure the background chain + * to a new DFS channel. + */ + if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 0; + if (!iface->radar_background.temp_ch) + return 0; + + iface->radar_background.temp_ch = 0; + return hostapd_dfs_start_channel_switch_background(iface); + } + /* * Just mark the channel available when CAC completion * event is received in enabled state. CAC result could @@ -912,6 +1167,9 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, iface->cac_started = 0; } } + } else if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 0; + hostpad_dfs_update_background_chain(iface); } return 0; @@ -940,7 +1198,8 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq, static struct hostapd_channel_data * dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, u8 *oper_centr_freq_seg0_idx, - u8 *oper_centr_freq_seg1_idx, int *skip_radar) + u8 *oper_centr_freq_seg1_idx, + enum dfs_channel_type *channel_type) { struct hostapd_channel_data *channel; @@ -948,22 +1207,22 @@ dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, channel = dfs_get_valid_channel(iface, secondary_channel, oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx, - *skip_radar); + *channel_type); if (channel) { wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d", channel->chan); return channel; } - if (*skip_radar) { - *skip_radar = 0; + if (*channel_type != DFS_ANY_CHANNEL) { + *channel_type = DFS_ANY_CHANNEL; } else { int oper_chwidth; oper_chwidth = hostapd_get_oper_chwidth(iface->conf); if (oper_chwidth == CHANWIDTH_USE_HT) break; - *skip_radar = 1; + *channel_type = DFS_AVAILABLE; hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1); } } @@ -981,7 +1240,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) int secondary_channel; u8 oper_centr_freq_seg0_idx = 0; u8 oper_centr_freq_seg1_idx = 0; - int skip_radar = 0; + enum dfs_channel_type channel_type = DFS_ANY_CHANNEL; int err = 1; /* Radar detected during active CAC */ @@ -989,13 +1248,13 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) channel = dfs_get_valid_channel(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - skip_radar); + channel_type); if (!channel) { channel = dfs_downgrade_bandwidth(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - &skip_radar); + &channel_type); if (!channel) { wpa_printf(MSG_ERROR, "No valid channel available"); return err; @@ -1022,20 +1281,61 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) } +static int +hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface, + int freq) +{ + if (!dfs_use_radar_background(iface)) + return -1; /* Background radar chain not supported. */ + + wpa_printf(MSG_DEBUG, + "%s called (background CAC active: %s, CSA active: %s)", + __func__, iface->radar_background.cac_started ? "yes" : "no", + hostapd_csa_in_progress(iface) ? "yes" : "no"); + + /* Check if CSA in progress */ + if (hostapd_csa_in_progress(iface)) + return 0; + + if (hostapd_dfs_is_background_event(iface, freq)) { + /* + * Radar pattern is reported on the background chain. + * Just select a new random channel according to the + * regulations for monitoring. + */ + hostpad_dfs_update_background_chain(iface); + return 0; + } + + /* + * If background radar detection is supported and the radar channel + * monitored by the background chain is available switch to it without + * waiting for the CAC. + */ + if (iface->radar_background.channel == -1) + return -1; /* Background radar chain not available. */ + + if (iface->radar_background.cac_started) { + /* + * Background channel not available yet. Perform CAC on the + * main chain. + */ + iface->radar_background.temp_ch = 1; + return -1; + } + + return hostapd_dfs_start_channel_switch_background(iface); +} + + static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; int secondary_channel; u8 oper_centr_freq_seg0_idx; u8 oper_centr_freq_seg1_idx; - u8 new_vht_oper_chwidth; - int skip_radar = 1; - struct csa_settings csa_settings; - unsigned int i; - int err = 1; - struct hostapd_hw_modes *cmode = iface->current_mode; + enum dfs_channel_type channel_type = DFS_AVAILABLE; u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); - int ieee80211_mode = IEEE80211_MODE_AP; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", @@ -1054,13 +1354,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) * uniform spreading. */ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) - skip_radar = 0; + channel_type = DFS_ANY_CHANNEL; /* Perform channel switch/CSA */ channel = dfs_get_valid_channel(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - skip_radar); + channel_type); if (!channel) { /* @@ -1068,11 +1368,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) * there is another channel where we can switch even if it * requires to perform a CAC first. */ - skip_radar = 0; + channel_type = DFS_ANY_CHANNEL; channel = dfs_downgrade_bandwidth(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - &skip_radar); + &channel_type); if (!channel) { /* * Toggle interface state to enter DFS state @@ -1083,7 +1383,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) return 0; } - if (!skip_radar) { + if (channel_type == DFS_ANY_CHANNEL) { iface->freq = channel->freq; iface->conf->channel = channel->chan; iface->conf->secondary_channel = secondary_channel; @@ -1098,73 +1398,12 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) } } - wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", - channel->chan); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL - "freq=%d chan=%d sec_chan=%d", channel->freq, - channel->chan, secondary_channel); - - new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); - hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth); - - /* Setup CSA request */ - os_memset(&csa_settings, 0, sizeof(csa_settings)); - csa_settings.cs_count = 5; - csa_settings.block_tx = 1; -#ifdef CONFIG_MESH - if (iface->mconf) - ieee80211_mode = IEEE80211_MODE_MESH; -#endif /* CONFIG_MESH */ - err = hostapd_set_freq_params(&csa_settings.freq_params, - 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, - secondary_channel, - new_vht_oper_chwidth, - oper_centr_freq_seg0_idx, - oper_centr_freq_seg1_idx, - cmode->vht_capab, - &cmode->he_capab[ieee80211_mode]); - - if (err) { - wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); - hostapd_disable_iface(iface); - return err; - } - - for (i = 0; i < iface->num_bss; i++) { - err = hostapd_switch_channel(iface->bss[i], &csa_settings); - if (err) - break; - } - - if (err) { - wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", - err); - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth); - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, - oper_centr_freq_seg0_idx); - hostapd_set_oper_centr_freq_seg1_idx(iface->conf, - oper_centr_freq_seg1_idx); - - hostapd_disable_iface(iface); - hostapd_enable_iface(iface); - return 0; - } - - /* Channel configuration will be updated once CSA completes and - * ch_switch_notify event is received */ - - wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); - return 0; + return hostapd_dfs_request_channel_switch(iface, channel->chan, + channel->freq, + secondary_channel, + current_vht_oper_chwidth, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx); } @@ -1172,8 +1411,6 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) { - int res; - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", freq, ht_enabled, chan_offset, chan_width, cf1, cf2); @@ -1186,20 +1423,23 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, return 0; /* mark radar frequency as invalid */ - res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, - cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); - if (!res) + if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, + cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE)) return 0; - /* Skip if reported radar event not overlapped our channels */ - res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); - if (!res) - return 0; + if (!hostapd_dfs_is_background_event(iface, freq)) { + /* Skip if reported radar event not overlapped our channels */ + if (!dfs_are_channels_overlapped(iface, freq, chan_width, + cf1, cf2)) + return 0; + } - /* radar detected while operating, switch the channel. */ - res = hostapd_dfs_start_channel_switch(iface); + if (hostapd_dfs_background_start_channel_switch(iface, freq)) { + /* Radar detected while operating, switch the channel. */ + return hostapd_dfs_start_channel_switch(iface); + } - return res; + return 0; } @@ -1219,9 +1459,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); - /* Handle cases where all channels were initially unavailable */ - if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) + if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) { + /* Handle cases where all channels were initially unavailable */ hostapd_handle_dfs(iface); + } else if (dfs_use_radar_background(iface) && + iface->radar_background.channel == -1) { + /* Reset radar background chain if disabled */ + hostpad_dfs_update_background_chain(iface); + } return 0; } @@ -1259,17 +1504,24 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, 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); + if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 1; + } else { + /* This is called when the driver indicates that an offloaded + * DFS has started CAC. */ + hostapd_set_state(iface, HAPD_IFACE_DFS); + iface->cac_started = 1; + } /* 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", + "seg1=%d cac_time=%ds%s", freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, - iface->dfs_cac_ms / 1000); - iface->cac_started = 1; + iface->dfs_cac_ms / 1000, + hostapd_dfs_is_background_event(iface, freq) ? + " (background)" : ""); + os_get_reltime(&iface->dfs_cac_start); return 0; } diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 96a13fb6..d4cbed88 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -31,6 +31,7 @@ static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd); static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, struct dpp_authentication *auth); +static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd); #ifdef CONFIG_DPP2 static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx); @@ -346,14 +347,8 @@ static int hostapd_dpp_pkex_done(void *ctx, void *conn, #endif /* CONFIG_DPP2 */ -enum hostapd_dpp_pkex_ver { - PKEX_VER_AUTO, - PKEX_VER_ONLY_1, - PKEX_VER_ONLY_2, -}; - static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, - enum hostapd_dpp_pkex_ver ver, + enum dpp_pkex_ver ver, const struct hostapd_ip_addr *ipaddr, int tcp_port) { @@ -1160,6 +1155,21 @@ static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd, } +#ifdef CONFIG_DPP3 +static void hostapd_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_authentication *auth = hapd->dpp_auth; + + if (!auth || !auth->waiting_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + hostapd_dpp_start_gas_client(hapd); +} +#endif /* CONFIG_DPP3 */ + + static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_ap_result result, const struct wpabuf *adv_proto, @@ -1169,6 +1179,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, const u8 *pos; struct dpp_authentication *auth = hapd->dpp_auth; enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; + int res; if (!auth || !auth->auth_success) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); @@ -1199,7 +1210,16 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, goto fail; } - if (dpp_conf_resp_rx(auth, resp) < 0) { + res = dpp_conf_resp_rx(auth, resp); +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, hostapd_dpp_build_new_key, hapd, + NULL); + return; + } +#endif /* CONFIG_DPP3 */ + if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; } @@ -1986,6 +2006,17 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR, MAC2STR(src)); + if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only"); + return; + } + if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only"); + return; + } + /* TODO: Support multiple PKEX codes by iterating over all the enabled * values here */ @@ -2349,6 +2380,13 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) if (!auth) return; +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key && ok) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", ok); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); @@ -2409,6 +2447,11 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) { struct dpp_bootstrap_info *own_bi; const char *pos, *end; +#ifdef CONFIG_DPP3 + enum dpp_pkex_ver ver = PKEX_VER_AUTO; +#else /* CONFIG_DPP3 */ + enum dpp_pkex_ver ver = PKEX_VER_ONLY_1; +#endif /* CONFIG_DPP3 */ int tcp_port = DPP_TCP_PORT; struct hostapd_ip_addr *ipaddr = NULL; #ifdef CONFIG_DPP2 @@ -2474,27 +2517,22 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) if (!hapd->dpp_pkex_code) return -1; + pos = os_strstr(cmd, " ver="); + if (pos) { + int v; + + pos += 5; + v = atoi(pos); + if (v == 1) + ver = PKEX_VER_ONLY_1; + else if (v == 2) + ver = PKEX_VER_ONLY_2; + else + return -1; + } + hapd->dpp_pkex_ver = ver; + if (os_strstr(cmd, " init=1")) { -#ifdef CONFIG_DPP3 - enum hostapd_dpp_pkex_ver ver = PKEX_VER_AUTO; -#else /* CONFIG_DPP3 */ - enum hostapd_dpp_pkex_ver ver = PKEX_VER_ONLY_1; -#endif /* CONFIG_DPP3 */ - - pos = os_strstr(cmd, " ver="); - if (pos) { - int v; - - pos += 5; - v = atoi(pos); - if (v == 1) - ver = PKEX_VER_ONLY_1; - else if (v == 2) - ver = PKEX_VER_ONLY_2; - else - return -1; - } - if (hostapd_dpp_pkex_init(hapd, ver, ipaddr, tcp_port) < 0) return -1; } else { @@ -2646,6 +2684,9 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) if (hapd->iface->interfaces) dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd); #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL); +#endif /* CONFIG_DPP3 */ dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; hostapd_dpp_pkex_remove(hapd, "*"); diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index f353a0ed..643a273b 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -261,12 +261,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } #endif /* NEED_AP_MLME */ -#ifdef CONFIG_INTERWORKING - if (elems.ext_capab && elems.ext_capab_len > 4) { - if (elems.ext_capab[4] & 0x01) - sta->qos_map_enabled = 1; - } -#endif /* CONFIG_INTERWORKING */ + check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len); #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); @@ -870,10 +865,11 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", + "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", finished ? "had" : "starting", freq, ht, hapd->iconf->ch_switch_vht_config, - hapd->iconf->ch_switch_he_config, offset, + hapd->iconf->ch_switch_he_config, + hapd->iconf->ch_switch_eht_config, offset, width, channel_width_to_string(width), cf1, cf2); if (!hapd->iface->current_mode) { @@ -953,9 +949,23 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, else if (hapd->iconf->ch_switch_he_config & CH_SWITCH_HE_DISABLED) hapd->iconf->ieee80211ax = 0; +#ifdef CONFIG_IEEE80211BE + } else if (hapd->iconf->ch_switch_eht_config) { + /* CHAN_SWITCH EHT config */ + if (hapd->iconf->ch_switch_eht_config & + CH_SWITCH_EHT_ENABLED) { + hapd->iconf->ieee80211be = 1; + hapd->iconf->ieee80211ax = 1; + if (!is_6ghz_freq(hapd->iface->freq)) + hapd->iconf->ieee80211ac = 1; + } else if (hapd->iconf->ch_switch_eht_config & + CH_SWITCH_EHT_DISABLED) + hapd->iconf->ieee80211be = 0; +#endif /* CONFIG_IEEE80211BE */ } hapd->iconf->ch_switch_vht_config = 0; hapd->iconf->ch_switch_he_config = 0; + hapd->iconf->ch_switch_eht_config = 0; if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 || width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160) @@ -1011,7 +1021,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hostapd_neighbor_set_own_report(hapd->iface->bss[i]); #ifdef CONFIG_OCV - if (hapd->conf->ocv) { + if (hapd->conf->ocv && + !(hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP)) { struct sta_info *sta; bool check_sa_query = false; @@ -2084,6 +2096,32 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->wds_sta_interface.ifname, data->wds_sta_interface.sta_addr); break; +#ifdef CONFIG_IEEE80211AX + case EVENT_BSS_COLOR_COLLISION: + /* The BSS color is shared amongst all BBSs on a specific phy. + * Therefore we always start the color change on the primary + * BSS. */ + wpa_printf(MSG_DEBUG, "BSS color collision on %s", + hapd->conf->iface); + hostapd_switch_color(hapd->iface->bss[0], + data->bss_color_collision.bitmap); + break; + case EVENT_CCA_STARTED_NOTIFY: + wpa_printf(MSG_DEBUG, "CCA started on on %s", + hapd->conf->iface); + break; + case EVENT_CCA_ABORTED_NOTIFY: + wpa_printf(MSG_DEBUG, "CCA aborted on on %s", + hapd->conf->iface); + hostapd_cleanup_cca_params(hapd); + break; + case EVENT_CCA_NOTIFY: + wpa_printf(MSG_DEBUG, "CCA finished on on %s", + hapd->conf->iface); + hapd->iface->conf->he_op.he_bss_color = hapd->cca_color; + hostapd_cleanup_cca_params(hapd); + break; +#endif /* CONFIG_IEEE80211AX */ default: wpa_printf(MSG_DEBUG, "Unknown event %d", event); break; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 4b88641a..ef53c41d 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -66,6 +66,10 @@ static int setup_interface2(struct hostapd_iface *iface); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); static void hostapd_interface_setup_failure_handler(void *eloop_ctx, void *timeout_ctx); +#ifdef CONFIG_IEEE80211AX +static void hostapd_switch_color_timeout_handler(void *eloop_data, + void *user_ctx); +#endif /* CONFIG_IEEE80211AX */ int hostapd_for_each_interface(struct hapd_interfaces *interfaces, @@ -462,6 +466,10 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) } eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL); #endif /* CONFIG_SAE */ + +#ifdef CONFIG_IEEE80211AX + eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL); +#endif /* CONFIG_IEEE80211AX */ } @@ -1458,14 +1466,14 @@ static int hostapd_set_acl_list(struct hostapd_data *hapd, } -static void hostapd_set_acl(struct hostapd_data *hapd) +int hostapd_set_acl(struct hostapd_data *hapd) { struct hostapd_config *conf = hapd->iconf; - int err; + int err = 0; u8 accept_acl; if (hapd->iface->drv_max_acl_mac_addrs == 0) - return; + return 0; if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) { accept_acl = 1; @@ -1474,7 +1482,7 @@ static void hostapd_set_acl(struct hostapd_data *hapd) accept_acl); if (err) { wpa_printf(MSG_DEBUG, "Failed to set accept acl"); - return; + return -1; } } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) { accept_acl = 0; @@ -1483,9 +1491,10 @@ static void hostapd_set_acl(struct hostapd_data *hapd) accept_acl); if (err) { wpa_printf(MSG_DEBUG, "Failed to set deny acl"); - return; + return -1; } } + return err; } @@ -2067,6 +2076,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, hapd->iconf->ieee80211n, hapd->iconf->ieee80211ac, hapd->iconf->ieee80211ax, + hapd->iconf->ieee80211be, hapd->iconf->secondary_channel, hostapd_get_oper_chwidth(hapd->iconf), hostapd_get_oper_centr_freq_seg0_idx( @@ -3452,12 +3462,14 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, conf->channel, conf->enable_edmg, conf->edmg_channel, conf->ieee80211n, conf->ieee80211ac, conf->ieee80211ax, - conf->secondary_channel, + conf->ieee80211be, conf->secondary_channel, hostapd_get_oper_chwidth(conf), hostapd_get_oper_centr_freq_seg0_idx(conf), hostapd_get_oper_centr_freq_seg1_idx(conf), conf->vht_capab, mode ? &mode->he_capab[IEEE80211_MODE_AP] : + NULL, + mode ? &mode->eht_capab[IEEE80211_MODE_AP] : NULL)) return -1; @@ -3545,11 +3557,12 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, &hapd->iface->cs_oper_class, &chan) == NUM_HOSTAPD_MODES) { wpa_printf(MSG_DEBUG, - "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)", + "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d)", settings->freq_params.freq, settings->freq_params.sec_channel_offset, settings->freq_params.vht_enabled, - settings->freq_params.he_enabled); + settings->freq_params.he_enabled, + settings->freq_params.eht_enabled); return -1; } @@ -3606,6 +3619,11 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd) void hostapd_chan_switch_config(struct hostapd_data *hapd, struct hostapd_freq_params *freq_params) { + if (freq_params->eht_enabled) + hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_ENABLED; + else + hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_DISABLED; + if (freq_params->he_enabled) hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED; else @@ -3618,7 +3636,8 @@ void hostapd_chan_switch_config(struct hostapd_data *hapd, hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "CHAN_SWITCH HE config 0x%x VHT config 0x%x", + "CHAN_SWITCH EHT config 0x%x HE config 0x%x VHT config 0x%x", + hapd->iconf->ch_switch_eht_config, hapd->iconf->ch_switch_he_config, hapd->iconf->ch_switch_vht_config); } @@ -3696,6 +3715,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, iface->conf->ieee80211n = freq_params->ht_enabled; iface->conf->ieee80211ac = freq_params->vht_enabled; iface->conf->ieee80211ax = freq_params->he_enabled; + iface->conf->ieee80211be = freq_params->eht_enabled; /* * cs_params must not be cleared earlier because the freq_params @@ -3706,6 +3726,139 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, hostapd_enable_iface(iface); } + +#ifdef CONFIG_IEEE80211AX + +void hostapd_cleanup_cca_params(struct hostapd_data *hapd) +{ + hapd->cca_count = 0; + hapd->cca_color = 0; + hapd->cca_c_off_beacon = 0; + hapd->cca_c_off_proberesp = 0; + hapd->cca_in_progress = false; +} + + +static int hostapd_fill_cca_settings(struct hostapd_data *hapd, + struct cca_settings *settings) +{ + struct hostapd_iface *iface = hapd->iface; + u8 old_color; + int ret; + + if (!iface || iface->conf->he_op.he_bss_color_disabled) + return -1; + + old_color = iface->conf->he_op.he_bss_color; + iface->conf->he_op.he_bss_color = hapd->cca_color; + ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); + if (ret) + return ret; + + iface->conf->he_op.he_bss_color = old_color; + + settings->cca_count = hapd->cca_count; + settings->cca_color = hapd->cca_color, + hapd->cca_in_progress = true; + + ret = hostapd_build_beacon_data(hapd, &settings->beacon_cca); + if (ret) { + free_beacon_data(&settings->beacon_after); + return ret; + } + + settings->counter_offset_beacon = hapd->cca_c_off_beacon; + settings->counter_offset_presp = hapd->cca_c_off_proberesp; + + return 0; +} + + +static void hostapd_switch_color_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_data; + os_time_t delta_t; + unsigned int b; + int i, r; + + /* CCA can be triggered once the handler constantly receives + * color collision events to for at least + * DOT11BSS_COLOR_COLLISION_AP_PERIOD (50 s by default). */ + delta_t = hapd->last_color_collision.sec - + hapd->first_color_collision.sec; + if (delta_t < DOT11BSS_COLOR_COLLISION_AP_PERIOD) + return; + + r = os_random() % HE_OPERATION_BSS_COLOR_MAX; + for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) { + if (r && !(hapd->color_collision_bitmap & BIT(r))) + break; + + r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX; + } + + if (i == HE_OPERATION_BSS_COLOR_MAX) { + /* There are no free colors so turn BSS coloring off */ + wpa_printf(MSG_INFO, + "No free colors left, turning off BSS coloring"); + hapd->iface->conf->he_op.he_bss_color_disabled = 1; + hapd->iface->conf->he_op.he_bss_color = os_random() % 63 + 1; + for (b = 0; b < hapd->iface->num_bss; b++) + ieee802_11_set_beacon(hapd->iface->bss[b]); + return; + } + + for (b = 0; b < hapd->iface->num_bss; b++) { + struct hostapd_data *bss = hapd->iface->bss[b]; + struct cca_settings settings; + int ret; + + hostapd_cleanup_cca_params(bss); + bss->cca_color = r; + bss->cca_count = 10; + + if (hostapd_fill_cca_settings(bss, &settings)) { + hostapd_cleanup_cca_params(bss); + continue; + } + + ret = hostapd_drv_switch_color(bss, &settings); + if (ret) + hostapd_cleanup_cca_params(bss); + + free_beacon_data(&settings.beacon_cca); + free_beacon_data(&settings.beacon_after); + } +} + + +void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap) +{ + struct os_reltime now; + + if (hapd->cca_in_progress) + return; + + if (os_get_reltime(&now)) + return; + + hapd->color_collision_bitmap = bitmap; + hapd->last_color_collision = now; + + if (eloop_is_timeout_registered(hostapd_switch_color_timeout_handler, + hapd, NULL)) + return; + + hapd->first_color_collision = now; + /* 10 s window as margin for persistent color collision reporting */ + eloop_register_timeout(DOT11BSS_COLOR_COLLISION_AP_PERIOD + 10, 0, + hostapd_switch_color_timeout_handler, + hapd, NULL); +} + +#endif /* CONFIG_IEEE80211AX */ + #endif /* NEED_AP_MLME */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 7f7877b8..6b9b65fb 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -14,6 +14,7 @@ #endif /* CONFIG_SQLITE */ #include "common/defs.h" +#include "common/dpp.h" #include "utils/list.h" #include "ap_config.h" #include "drivers/driver.h" @@ -207,6 +208,7 @@ struct hostapd_data { void *ssl_ctx; void *eap_sim_db_priv; + struct crypto_rsa_key *imsi_privacy_key; struct radius_server_data *radius_srv; struct dl_list erp_keys; /* struct eap_server_erp_key */ @@ -294,6 +296,17 @@ struct hostapd_data { unsigned int cs_c_off_ecsa_beacon; unsigned int cs_c_off_ecsa_proberesp; +#ifdef CONFIG_IEEE80211AX + bool cca_in_progress; + u8 cca_count; + u8 cca_color; + unsigned int cca_c_off_beacon; + unsigned int cca_c_off_proberesp; + struct os_reltime first_color_collision; + struct os_reltime last_color_collision; + u64 color_collision_bitmap; +#endif /* CONFIG_IEEE80211AX */ + #ifdef CONFIG_P2P struct p2p_data *p2p; struct p2p_group *p2p_group; @@ -388,6 +401,7 @@ struct hostapd_data { struct dpp_bootstrap_info *dpp_pkex_bi; char *dpp_pkex_code; char *dpp_pkex_identifier; + enum dpp_pkex_ver dpp_pkex_ver; char *dpp_pkex_auth_cmd; char *dpp_configurator_params; struct os_reltime dpp_last_init; @@ -521,6 +535,21 @@ struct hostapd_iface { int *basic_rates; int freq; + /* Background radar configuration */ + struct { + int channel; + int secondary_channel; + int freq; + int centr_freq_seg0_idx; + int centr_freq_seg1_idx; + /* Main chain is on temporary channel during + * CAC detection on radar offchain. + */ + unsigned int temp_ch:1; + /* CAC started on radar offchain */ + unsigned int cac_started:1; + } radar_background; + u16 hw_flags; /* Number of associated Non-ERP stations (i.e., stations using 802.11b @@ -648,6 +677,9 @@ void hostapd_periodic_iface(struct hostapd_iface *iface); int hostapd_owe_trans_get_info(struct hostapd_data *hapd); void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx); +void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap); +void hostapd_cleanup_cca_params(struct hostapd_data *hapd); + /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, @@ -693,4 +725,6 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, struct fst_wpa_obj *iface_obj); #endif /* CONFIG_FST */ +int hostapd_set_acl(struct hostapd_data *hapd); + #endif /* HOSTAPD_H */ diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 6140a492..394e292b 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -498,6 +498,7 @@ static const char * sae_get_password(struct hostapd_data *hapd, struct sae_password_entry *pw; struct sae_pt *pt = NULL; const struct sae_pk *pk = NULL; + struct hostapd_sta_wpa_psk_short *psk = NULL; for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) { if (!is_broadcast_ether_addr(pw->peer_addr) && @@ -519,6 +520,15 @@ static const char * sae_get_password(struct hostapd_data *hapd, pt = hapd->conf->ssid.pt; } + if (!password) { + for (psk = sta->psk; psk; psk = psk->next) { + if (psk->is_passphrase) { + password = psk->passphrase; + break; + } + } + } + if (pw_entry) *pw_entry = pw; if (s_pt) @@ -2315,9 +2325,8 @@ static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, } -static int -ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, - int res, struct radius_sta *info) +int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, + int res, struct radius_sta *info) { u32 session_timeout = info->session_timeout; u32 acct_interim_interval = info->acct_interim_interval; @@ -3112,6 +3121,7 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, int ret, inc_y; bool derive_keys; u32 i; + bool derive_kdk; if (!groups) groups = default_groups; @@ -3151,10 +3161,14 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, sta->pasn->akmp = rsn_data.key_mgmt; sta->pasn->cipher = rsn_data.pairwise_cipher; - if (hapd->conf->force_kdk_derivation || - ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) && - ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, - WLAN_RSNX_CAPAB_SECURE_LTF))) + derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) && + ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SECURE_LTF); +#ifdef CONFIG_TESTING_OPTIONS + if (!derive_kdk) + derive_kdk = hapd->conf->force_kdk_derivation; +#endif /* CONFIG_TESTING_OPTIONS */ + if (derive_kdk) sta->pasn->kdk_len = WPA_KDK_MAX_LEN; else sta->pasn->kdk_len = 0; @@ -4123,32 +4137,6 @@ static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, } -static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ext_capab_ie, size_t ext_capab_ie_len) -{ -#ifdef CONFIG_INTERWORKING - /* check for QoS Map support */ - if (ext_capab_ie_len >= 5) { - if (ext_capab_ie[4] & 0x01) - sta->qos_map_enabled = 1; - } -#endif /* CONFIG_INTERWORKING */ - - if (ext_capab_ie_len > 0) { - sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); - os_free(sta->ext_capability); - sta->ext_capability = os_malloc(1 + ext_capab_ie_len); - if (sta->ext_capability) { - sta->ext_capability[0] = ext_capab_ie_len; - os_memcpy(sta->ext_capability + 1, ext_capab_ie, - ext_capab_ie_len); - } - } - - return WLAN_STATUS_SUCCESS; -} - - #ifdef CONFIG_OWE static int owe_group_supported(struct hostapd_data *hapd, u16 group) @@ -4203,8 +4191,21 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd, else return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - crypto_ecdh_deinit(sta->owe_ecdh); - sta->owe_ecdh = crypto_ecdh_init(group); + if (sta->owe_group == group && sta->owe_ecdh) { + /* This is a workaround for mac80211 behavior of retransmitting + * the Association Request frames multiple times if the link + * layer retries (i.e., seq# remains same) fail. The mac80211 + * initiated retransmission will use a different seq# and as + * such, will go through duplicate detection. If we were to + * change our DH key for that attempt, there would be two + * different DH shared secrets and the STA would likely select + * the wrong one. */ + wpa_printf(MSG_DEBUG, + "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again"); + } else { + crypto_ecdh_deinit(sta->owe_ecdh); + sta->owe_ecdh = crypto_ecdh_init(group); + } if (!sta->owe_ecdh) return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; sta->owe_group = group; @@ -4553,6 +4554,17 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP, + elems.he_capabilities, + elems.he_capabilities_len, + elems.eht_capabilities, + elems.eht_capabilities_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + } +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_P2P if (elems.p2p) { @@ -4924,6 +4936,7 @@ static int add_associated_sta(struct hostapd_data *hapd, struct ieee80211_ht_capabilities ht_cap; struct ieee80211_vht_capabilities vht_cap; struct ieee80211_he_capabilities he_cap; + struct ieee80211_eht_capabilities eht_cap; int set = 1; /* @@ -4980,6 +4993,11 @@ static int add_associated_sta(struct hostapd_data *hapd, sta->he_capab_len); } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (sta->flags & WLAN_STA_EHT) + hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap, + sta->eht_capab_len); +#endif /* CONFIG_IEEE80211BE */ /* * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags @@ -4993,6 +5011,8 @@ static int add_associated_sta(struct hostapd_data *hapd, sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, sta->flags & WLAN_STA_HE ? &he_cap : NULL, sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0, + sta->flags & WLAN_STA_EHT ? &eht_cap : NULL, + sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0, sta->he_6ghz_capab, sta->flags | WLAN_STA_ASSOC, sta->qosinfo, sta->vht_opmode, sta->p2p_ie ? 1 : 0, @@ -5043,6 +5063,13 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, if (sta && sta->dpp_pfs) buflen += 5 + sta->dpp_pfs->curve->prime_len; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP); + buflen += 3 + sizeof(struct ieee80211_eht_operation); + } +#endif /* CONFIG_IEEE80211BE */ + buf = os_zalloc(buflen); if (!buf) { res = WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -5151,6 +5178,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP); p = hostapd_eid_he_operation(hapd, p); + p = hostapd_eid_cca(hapd, p); p = hostapd_eid_spatial_reuse(hapd, p); p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); p = hostapd_eid_he_6ghz_band_cap(hapd, p); @@ -5188,6 +5216,13 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, rsnxe_done: #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP); + p = hostapd_eid_eht_operation(hapd, p); + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS && @@ -6903,6 +6938,38 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, } +static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count, + enum max_tx_pwr_interpretation tx_pwr_intrpn, + u8 tx_pwr_cat, u8 tx_pwr) +{ + int i; + + *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */ + *eid++ = 2 + tx_pwr_count; /* Length */ + + /* + * Transmit Power Information field + * bits 0-2 : Maximum Transmit Power Count + * bits 3-5 : Maximum Transmit Power Interpretation + * bits 6-7 : Maximum Transmit Power Category + */ + *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6); + + /* Maximum Transmit Power field */ + for (i = 0; i <= tx_pwr_count; i++) + *eid++ = tx_pwr; + + return eid; +} + + +/* + * TODO: Extract power limits from channel data after 6G regulatory + * support. + */ +#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */ +#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */ + u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) { struct hostapd_iface *iface = hapd->iface; @@ -6927,6 +6994,43 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) if (i == mode->num_channels) return eid; +#ifdef CONFIG_IEEE80211AX + /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United + * States): An AP that is an Indoor Access Point per regulatory rules + * shall send at least two Transmit Power Envelope elements in Beacon + * and Probe Response frames as follows: + * - Maximum Transmit Power Category subfield = Default; + * Unit interpretation = Regulatory client EIRP PSD + * - Maximum Transmit Power Category subfield = Subordinate Device; + * Unit interpretation = Regulatory client EIRP PSD + */ + if (is_6ghz_op_class(iconf->op_class)) { + enum max_tx_pwr_interpretation tx_pwr_intrpn; + + /* Same Maximum Transmit Power for all 20 MHz bands */ + tx_pwr_count = 0; + tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD; + + /* Default Transmit Power Envelope for Global Operating Class */ + tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2; + eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn, + REG_DEFAULT_CLIENT, tx_pwr); + + /* Indoor Access Point must include an additional TPE for + * subordinate devices */ + if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) { + /* TODO: Extract PSD limits from channel data */ + tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2; + eid = hostapd_add_tpe_info(eid, tx_pwr_count, + tx_pwr_intrpn, + REG_SUBORDINATE_CLIENT, + tx_pwr); + } + + return eid; + } +#endif /* CONFIG_IEEE80211AX */ + switch (hostapd_get_oper_chwidth(iconf)) { case CHANWIDTH_USE_HT: if (iconf->secondary_channel == 0) { @@ -6999,19 +7103,9 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) else tx_pwr = max_tx_power; - *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; - *eid++ = 2 + tx_pwr_count; - - /* - * Max Transmit Power count and - * Max Transmit Power units = 0 (EIRP) - */ - *eid++ = tx_pwr_count; - - for (i = 0; i <= tx_pwr_count; i++) - *eid++ = tx_pwr; - - return eid; + return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP, + 0 /* Reserved for bands other than 6 GHz */, + tx_pwr); } @@ -7022,7 +7116,8 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid) if (!hapd->cs_freq_params.channel || (!hapd->cs_freq_params.vht_enabled && - !hapd->cs_freq_params.he_enabled)) + !hapd->cs_freq_params.he_enabled && + !hapd->cs_freq_params.eht_enabled)) return eid; /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */ diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index c59ad5e3..fa1f47b9 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -78,6 +78,10 @@ void hostapd_get_he_capab(struct hostapd_data *hapd, const struct ieee80211_he_capabilities *he_cap, struct ieee80211_he_capabilities *neg_he_cap, size_t he_capab_len); +void hostapd_get_eht_capab(struct hostapd_data *hapd, + const struct ieee80211_eht_capabilities *src, + struct ieee80211_eht_capabilities *dest, + size_t len); int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta); u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ht_capab); @@ -100,6 +104,7 @@ u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *he_6ghz_capab); int hostapd_get_he_twt_responder(struct hostapd_data *hapd, enum ieee80211_op_mode mode); +u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len, int ack); void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, @@ -194,7 +199,20 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth, void auth_sae_process_commit(void *eloop_ctx, void *user_ctx); u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len); +u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ext_capab_ie, size_t ext_capab_ie_len); size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type); u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type); +int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, + int res, struct radius_sta *info); +size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd, + enum ieee80211_op_mode opmode); +u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid, + enum ieee80211_op_mode opmode); +u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid); +u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, + enum ieee80211_op_mode opmode, + const u8 *he_capab, size_t he_capab_len, + const u8 *eht_capab, size_t eht_capab_len); #endif /* IEEE802_11_H */ diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c index 783ee6de..4277d82c 100644 --- a/src/ap/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2012, Jouni Malinen + * Copyright (c) 2003-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,8 @@ #include "hostapd.h" #include "ap_config.h" #include "ap_drv_ops.h" +#include "sta_info.h" +#include "wpa_auth.h" #include "ieee802_11.h" #include "ieee802_1x.h" #include "ieee802_11_auth.h" @@ -43,6 +45,11 @@ struct hostapd_acl_query_data { u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ size_t auth_msg_len; struct hostapd_acl_query_data *next; + bool radius_psk; + int akm; + u8 *anonce; + u8 *eapol; + size_t eapol_len; }; @@ -95,9 +102,11 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) { - if (query == NULL) + if (!query) return; os_free(query->auth_msg); + os_free(query->anonce); + os_free(query->eapol); os_free(query); } @@ -111,7 +120,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, query->radius_id = radius_client_get_id(hapd->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); - if (msg == NULL) + if (!msg) return -1; if (radius_msg_make_authenticator(msg) < 0) { @@ -153,6 +162,31 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, goto fail; } + if (query->akm && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, + wpa_akm_to_suite(query->akm))) { + wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite"); + goto fail; + } + + if (query->anonce && + !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, + RADIUS_VENDOR_ID_FREERADIUS, + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE, + query->anonce, WPA_NONCE_LEN)) { + wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce"); + goto fail; + } + + if (query->eapol && + !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, + RADIUS_VENDOR_ID_FREERADIUS, + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG, + query->eapol, query->eapol_len)) { + wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg"); + goto fail; + } + if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0) goto fail; return 0; @@ -260,23 +294,23 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, /* No entry in the cache - query external RADIUS server */ query = os_zalloc(sizeof(*query)); - if (query == NULL) { + if (!query) { wpa_printf(MSG_ERROR, "malloc for query data failed"); return HOSTAPD_ACL_REJECT; } os_get_reltime(&query->timestamp); os_memcpy(query->addr, addr, ETH_ALEN); if (hostapd_radius_acl_query(hapd, addr, query)) { - wpa_printf(MSG_DEBUG, "Failed to send Access-Request " - "for ACL query."); + wpa_printf(MSG_DEBUG, + "Failed to send Access-Request for ACL query."); hostapd_acl_query_free(query); return HOSTAPD_ACL_REJECT; } query->auth_msg = os_memdup(msg, len); - if (query->auth_msg == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for " - "auth frame."); + if (!query->auth_msg) { + wpa_printf(MSG_ERROR, + "Failed to allocate memory for auth frame."); hostapd_acl_query_free(query); return HOSTAPD_ACL_REJECT; } @@ -392,7 +426,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd, * Passphrase is NULL iff there is no i-th Tunnel-Password * attribute in msg. */ - if (passphrase == NULL) + if (!passphrase) break; /* @@ -464,28 +498,30 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, prev = query; query = query->next; } - if (query == NULL) + if (!query) return RADIUS_RX_UNKNOWN; - wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " - "message (id=%d)", query->radius_id); + wpa_printf(MSG_DEBUG, + "Found matching Access-Request for RADIUS message (id=%d)", + query->radius_id); if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { - wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " - "correct authenticator - dropped\n"); + wpa_printf(MSG_INFO, + "Incoming RADIUS packet did not have correct authenticator - dropped"); return RADIUS_RX_INVALID_AUTHENTICATOR; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT) { - wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " - "query", hdr->code); + wpa_printf(MSG_DEBUG, + "Unknown RADIUS message code %d to ACL query", + hdr->code); return RADIUS_RX_UNKNOWN; } /* Insert Accept/Reject info into ACL cache */ cache = os_zalloc(sizeof(*cache)); - if (cache == NULL) { + if (!cache) { wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); goto done; } @@ -506,8 +542,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, &info->acct_interim_interval) == 0 && info->acct_interim_interval < 60) { - wpa_printf(MSG_DEBUG, "Ignored too small " - "Acct-Interim-Interval %d for STA " MACSTR, + wpa_printf(MSG_DEBUG, + "Ignored too small Acct-Interim-Interval %d for STA " + MACSTR, info->acct_interim_interval, MAC2STR(query->addr)); info->acct_interim_interval = 0; @@ -557,20 +594,43 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, cache->next = hapd->acl_cache; hapd->acl_cache = cache; + if (query->radius_psk) { + struct sta_info *sta; + bool success = cache->accepted == HOSTAPD_ACL_ACCEPT; + + sta = ap_get_sta(hapd, query->addr); + if (!sta || !sta->wpa_sm) { + wpa_printf(MSG_DEBUG, + "No STA/SM entry found for the RADIUS PSK response"); + goto done; + } +#ifdef NEED_AP_MLME + if (success && + (ieee802_11_set_radius_info(hapd, sta, cache->accepted, + info) < 0 || + ap_sta_bind_vlan(hapd, sta) < 0)) + success = false; +#endif /* NEED_AP_MLME */ + wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success); + } else { #ifdef CONFIG_DRIVER_RADIUS_ACL - hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, - info->session_timeout); + hostapd_drv_set_radius_acl_auth(hapd, query->addr, + cache->accepted, + info->session_timeout); #else /* CONFIG_DRIVER_RADIUS_ACL */ #ifdef NEED_AP_MLME - /* Re-send original authentication frame for 802.11 processing */ - wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " - "successful RADIUS ACL query"); - ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); + /* Re-send original authentication frame for 802.11 processing + */ + wpa_printf(MSG_DEBUG, + "Re-sending authentication frame after successful RADIUS ACL query"); + ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, + NULL); #endif /* NEED_AP_MLME */ #endif /* CONFIG_DRIVER_RADIUS_ACL */ + } done: - if (prev == NULL) + if (!prev) hapd->acl_queries = query->next; else prev->next = query->next; @@ -646,6 +706,40 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk) while (psk) { struct hostapd_sta_wpa_psk_short *prev = psk; psk = psk->next; - os_free(prev); + bin_clear_free(prev, sizeof(*prev)); } } + + +#ifndef CONFIG_NO_RADIUS +void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr, + int key_mgmt, const u8 *anonce, + const u8 *eapol, size_t eapol_len) +{ + struct hostapd_acl_query_data *query; + + query = os_zalloc(sizeof(*query)); + if (!query) + return; + + query->radius_psk = true; + query->akm = key_mgmt; + os_get_reltime(&query->timestamp); + os_memcpy(query->addr, addr, ETH_ALEN); + if (anonce) + query->anonce = os_memdup(anonce, WPA_NONCE_LEN); + if (eapol) { + query->eapol = os_memdup(eapol, eapol_len); + query->eapol_len = eapol_len; + } + if (hostapd_radius_acl_query(hapd, addr, query)) { + wpa_printf(MSG_DEBUG, + "Failed to send Access-Request for RADIUS PSK/ACL query"); + hostapd_acl_query_free(query); + return; + } + + query->next = hapd->acl_queries; + hapd->acl_queries = query; +} +#endif /* CONFIG_NO_RADIUS */ diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h index 9410f55c..22ae1a9d 100644 --- a/src/ap/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2005, Jouni Malinen + * Copyright (c) 2003-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -36,5 +36,8 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk); void hostapd_acl_expire(struct hostapd_data *hapd); void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, struct hostapd_sta_wpa_psk_short *src); +void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr, + int key_mgmt, const u8 *anonce, + const u8 *eapol, size_t eapol_len); #endif /* IEEE802_11_AUTH_H */ diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c new file mode 100644 index 00000000..dbbf9a60 --- /dev/null +++ b/src/ap/ieee802_11_eht.c @@ -0,0 +1,353 @@ +/* + * hostapd / IEEE 802.11be EHT + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. + * + * 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 "hostapd.h" +#include "sta_info.h" +#include "ieee802_11.h" + + +static u16 ieee80211_eht_ppet_size(u16 ppe_thres_hdr, const u8 *phy_cap_info) +{ + u8 ru; + u16 sz = 0; + + if ((phy_cap_info[EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] & + EHT_PHYCAP_PPE_THRESHOLD_PRESENT) == 0) + return 0; + + ru = (ppe_thres_hdr & + EHT_PPE_THRES_RU_INDEX_MASK) >> EHT_PPE_THRES_RU_INDEX_SHIFT; + while (ru) { + if (ru & 0x1) + sz++; + ru >>= 1; + } + + sz = sz * (1 + ((ppe_thres_hdr & EHT_PPE_THRES_NSS_MASK) >> + EHT_PPE_THRES_NSS_SHIFT)); + sz = (sz * 6) + 9; + if (sz % 8) + sz += 8; + sz /= 8; + + return sz; +} + + +static u8 ieee80211_eht_mcs_set_size(const u8 *he_phy_cap, + const u8 *eht_phy_cap) +{ + u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; + + if ((he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0) + return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY; + + if (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) + sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; + + if (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & + EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK) + sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; + + return sz; +} + + +size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd, + enum ieee80211_op_mode opmode) +{ + struct hostapd_hw_modes *mode; + struct eht_capabilities *eht_cap; + size_t len = 3 + 2 + EHT_PHY_CAPAB_LEN; + + mode = hapd->iface->current_mode; + if (!mode) + return 0; + + eht_cap = &mode->eht_capab[opmode]; + if (!eht_cap->eht_supported) + return 0; + + len += ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap, + eht_cap->phy_cap); + len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]), + eht_cap->phy_cap); + + return len; +} + + +u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid, + enum ieee80211_op_mode opmode) +{ + struct hostapd_hw_modes *mode; + struct eht_capabilities *eht_cap; + struct ieee80211_eht_capabilities *cap; + size_t mcs_nss_len, ppe_thresh_len; + u8 *pos = eid, *length_pos; + + mode = hapd->iface->current_mode; + if (!mode) + return eid; + + eht_cap = &mode->eht_capab[opmode]; + if (!eht_cap->eht_supported) + return eid; + + *pos++ = WLAN_EID_EXTENSION; + length_pos = pos++; + *pos++ = WLAN_EID_EXT_EHT_CAPABILITIES; + + cap = (struct ieee80211_eht_capabilities *) pos; + os_memset(cap, 0, sizeof(*cap)); + cap->mac_cap = host_to_le16(eht_cap->mac_cap); + os_memcpy(cap->phy_cap, eht_cap->phy_cap, EHT_PHY_CAPAB_LEN); + + if (!is_6ghz_op_class(hapd->iconf->op_class)) + cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &= + ~EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK; + if (!hapd->iface->conf->eht_phy_capab.su_beamformer) + cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMER_IDX] &= + ~EHT_PHYCAP_SU_BEAMFORMER; + + if (!hapd->iface->conf->eht_phy_capab.su_beamformee) + cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMEE_IDX] &= + ~EHT_PHYCAP_SU_BEAMFORMEE; + + if (!hapd->iface->conf->eht_phy_capab.mu_beamformer) + cap->phy_cap[EHT_PHYCAP_MU_BEAMFORMER_IDX] &= + ~EHT_PHYCAP_MU_BEAMFORMER_MASK; + + pos = cap->optional; + + mcs_nss_len = ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap, + eht_cap->phy_cap); + if (mcs_nss_len) { + os_memcpy(pos, eht_cap->mcs, mcs_nss_len); + pos += mcs_nss_len; + } + + ppe_thresh_len = ieee80211_eht_ppet_size( + WPA_GET_LE16(&eht_cap->ppet[0]), + eht_cap->phy_cap); + if (ppe_thresh_len) { + os_memcpy(pos, eht_cap->ppet, ppe_thresh_len); + pos += ppe_thresh_len; + } + + *length_pos = pos - (eid + 2); + return pos; +} + + +u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid) +{ + struct hostapd_config *conf = hapd->iconf; + struct ieee80211_eht_operation *oper; + u8 *pos = eid, chwidth, seg0 = 0, seg1 = 0; + + if (!hapd->iface->current_mode) + return eid; + + *pos++ = WLAN_EID_EXTENSION; + *pos++ = 5; + *pos++ = WLAN_EID_EXT_EHT_OPERATION; + + oper = (struct ieee80211_eht_operation *) pos; + oper->oper_params = EHT_OPER_INFO_PRESENT; + + if (is_6ghz_op_class(conf->op_class)) + chwidth = op_class_to_ch_width(conf->op_class); + else + chwidth = conf->eht_oper_chwidth; + + seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf); + + switch (chwidth) { +#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal + * needs to be able to define this. */ + case CHANWIDTH_320MHZ: + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ; + seg1 = seg0; + if (hapd->iconf->channel < seg0) + seg0 -= 16; + else + seg0 += 16; + break; +#endif + case CHANWIDTH_160MHZ: + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ; + seg1 = seg0; + if (hapd->iconf->channel < seg0) + seg0 -= 8; + else + seg0 += 8; + break; + case CHANWIDTH_80MHZ: + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ; + break; + case CHANWIDTH_USE_HT: + if (seg0) + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ; + break; + default: + return eid; + } + + oper->oper_info.ccfs0 = seg0 ? seg0 : hapd->iconf->channel; + oper->oper_info.ccfs1 = seg1; + + return pos + 4; +} + + +static bool check_valid_eht_mcs_nss(struct hostapd_data *hapd, const u8 *ap_mcs, + const u8 *sta_mcs, u8 mcs_count, u8 map_len) +{ + unsigned int i, j; + + for (i = 0; i < mcs_count; i++) { + ap_mcs += i * 3; + sta_mcs += i * 3; + + for (j = 0; j < map_len; j++) { + if (((ap_mcs[j] >> 4) & 0xFF) == 0) + continue; + + if ((sta_mcs[j] & 0xFF) == 0) + continue; + + return true; + } + } + + wpa_printf(MSG_DEBUG, + "No matching EHT MCS found between AP TX and STA RX"); + return false; +} + + +static bool check_valid_eht_mcs(struct hostapd_data *hapd, + const u8 *sta_eht_capab, + enum ieee80211_op_mode opmode) +{ + struct hostapd_hw_modes *mode; + const struct ieee80211_eht_capabilities *capab; + const u8 *ap_mcs, *sta_mcs; + u8 mcs_count = 1; + + mode = hapd->iface->current_mode; + if (!mode) + return true; + + ap_mcs = mode->eht_capab[opmode].mcs; + capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab; + sta_mcs = capab->optional; + + if (ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap, + mode->eht_capab[opmode].phy_cap) == + EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY) + return check_valid_eht_mcs_nss( + hapd, ap_mcs, sta_mcs, 1, + EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY); + + switch (hapd->iface->conf->eht_oper_chwidth) { + /* TODO: CHANWIDTH_320MHZ */ + case CHANWIDTH_80P80MHZ: + case CHANWIDTH_160MHZ: + mcs_count = 2; + break; + } + + return check_valid_eht_mcs_nss(hapd, ap_mcs, sta_mcs, mcs_count, + EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS); +} + + +static bool ieee80211_invalid_eht_cap_size(const u8 *he_cap, const u8 *eht_cap, + size_t len) +{ + const struct ieee80211_he_capabilities *he_capab; + struct ieee80211_eht_capabilities *cap; + const u8 *he_phy_cap; + size_t cap_len; + u16 ppe_thres_hdr; + + he_capab = (const struct ieee80211_he_capabilities *) he_cap; + he_phy_cap = he_capab->he_phy_capab_info; + cap = (struct ieee80211_eht_capabilities *) eht_cap; + cap_len = sizeof(*cap) - sizeof(cap->optional); + if (len < cap_len) + return true; + + cap_len += ieee80211_eht_mcs_set_size(he_phy_cap, cap->phy_cap); + if (len < cap_len) + return true; + + ppe_thres_hdr = len > cap_len + 1 ? + WPA_GET_LE16(&eht_cap[cap_len]) : 0x01ff; + cap_len += ieee80211_eht_ppet_size(ppe_thres_hdr, cap->phy_cap); + + return len < cap_len; +} + + +u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, + enum ieee80211_op_mode opmode, + const u8 *he_capab, size_t he_capab_len, + const u8 *eht_capab, size_t eht_capab_len) +{ + if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be || + !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN || + !eht_capab || + ieee80211_invalid_eht_cap_size(he_capab, eht_capab, + eht_capab_len) || + !check_valid_eht_mcs(hapd, eht_capab, opmode)) { + sta->flags &= ~WLAN_STA_EHT; + os_free(sta->eht_capab); + sta->eht_capab = NULL; + return WLAN_STATUS_SUCCESS; + } + + os_free(sta->eht_capab); + sta->eht_capab = os_memdup(eht_capab, eht_capab_len); + if (!sta->eht_capab) { + sta->eht_capab_len = 0; + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_EHT; + sta->eht_capab_len = eht_capab_len; + + return WLAN_STATUS_SUCCESS; +} + + +void hostapd_get_eht_capab(struct hostapd_data *hapd, + const struct ieee80211_eht_capabilities *src, + struct ieee80211_eht_capabilities *dest, + size_t len) +{ + if (!src || !dest) + return; + + if (len > sizeof(*dest)) + len = sizeof(*dest); + /* TODO: mask out unsupported features */ + + os_memset(dest, 0, sizeof(*dest)); + os_memcpy(dest, src, len); +} diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c index 6cd6c90d..1e74c584 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -29,17 +29,19 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) & HE_PPE_THRES_RU_INDEX_BITMASK_MASK; + /* Count the number of 1 bits in RU Index Bitmask */ while (ru) { if (ru & 0x1) sz++; ru >>= 1; } + /* fixed header of 3 (NSTS) + 4 (RU Index Bitmask) = 7 bits */ + /* 6 * (NSTS + 1) bits for bit 1 in RU Index Bitmask */ sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK); sz = (sz * 6) + 7; - if (sz % 8) - sz += 8; - sz /= 8; + /* PPE Pad to count the number of needed full octets */ + sz = (sz + 7) / 8; return sz; } @@ -64,6 +66,7 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len) { struct ieee80211_he_capabilities *cap; size_t cap_len; + u8 ppe_thres_hdr; cap = (struct ieee80211_he_capabilities *) buf; cap_len = sizeof(*cap) - sizeof(cap->optional); @@ -74,9 +77,11 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len) if (len < cap_len) return 1; - cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info); + ppe_thres_hdr = len > cap_len ? buf[cap_len] : 0xff; + cap_len += ieee80211_he_ppet_size(ppe_thres_hdr, + cap->he_phy_capab_info); - return len != cap_len; + return len < cap_len; } @@ -195,7 +200,8 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) if (hapd->iface->conf->he_op.he_er_su_disable) params |= HE_OPERATION_ER_SU_DISABLE; - if (hapd->iface->conf->he_op.he_bss_color_disabled) + if (hapd->iface->conf->he_op.he_bss_color_disabled || + hapd->cca_in_progress) params |= HE_OPERATION_BSS_COLOR_DISABLED; if (hapd->iface->conf->he_op.he_bss_color_partial) params |= HE_OPERATION_BSS_COLOR_PARTIAL; @@ -213,6 +219,7 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) if (is_6ghz_op_class(hapd->iconf->op_class)) { u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); + u8 control; if (!seg0) seg0 = hapd->iconf->channel; @@ -220,16 +227,28 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) params |= HE_OPERATION_6GHZ_OPER_INFO; /* 6 GHz Operation Information field - * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element, + * IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element, * Figure 9-788k */ *pos++ = hapd->iconf->channel; /* Primary Channel */ - /* Control: Channel Width */ + /* Control: + * bits 0-1: Channel Width + * bit 2: Duplicate Beacon + * bits 3-5: Regulatory Info + */ + /* Channel Width */ if (seg1) - *pos++ = 3; + control = 3; else - *pos++ = center_idx_to_bw_6ghz(seg0); + control = center_idx_to_bw_6ghz(seg0); + if (hapd->iconf->he_6ghz_reg_pwr_type == 1) + control |= HE_6GHZ_STANDARD_POWER_AP << + HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT; + else + control |= HE_6GHZ_INDOOR_AP << + HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT; + *pos++ = control; /* Channel Center Freq Seg0/Seg1 */ if (hapd->iconf->he_oper_chwidth == 2) { @@ -520,3 +539,19 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd, return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) && hapd->iface->conf->he_op.he_twt_responder; } + + +u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid) +{ + if (!hapd->cca_in_progress) + return eid; + + /* BSS Color Change Announcement element */ + *eid++ = WLAN_EID_EXTENSION; + *eid++ = 3; + *eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT; + *eid++ = hapd->cca_count; /* Color Switch Countdown */ + *eid++ = hapd->cca_color; /* New BSS Color Information */ + + return eid; +} diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index 4bff9e59..61548951 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -1093,3 +1093,29 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len) return pos; } + + +u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ext_capab_ie, size_t ext_capab_ie_len) +{ +#ifdef CONFIG_INTERWORKING + /* check for QoS Map support */ + if (ext_capab_ie_len >= 5) { + if (ext_capab_ie[4] & 0x01) + sta->qos_map_enabled = 1; + } +#endif /* CONFIG_INTERWORKING */ + + if (ext_capab_ie_len > 0) { + sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); + os_free(sta->ext_capability); + sta->ext_capability = os_malloc(1 + ext_capab_ie_len); + if (sta->ext_capability) { + sta->ext_capability[0] = ext_capab_ie_len; + os_memcpy(sta->ext_capability + 1, ext_capab_ie, + ext_capab_ie_len); + } + } + + return WLAN_STATUS_SUCCESS; +} diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 753c8833..fb5e9206 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -2448,6 +2448,9 @@ int ieee802_1x_init(struct hostapd_data *hapd) 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; +#ifdef CONFIG_TESTING_OPTIONS + conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ os_memset(&cb, 0, sizeof(cb)); cb.eapol_send = ieee802_1x_eapol_send; diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c index 229edd2a..e37324f3 100644 --- a/src/ap/neighbor_db.c +++ b/src/ap/neighbor_db.c @@ -225,6 +225,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax; + bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be; struct wpa_ssid_value ssid; u8 channel, op_class; u8 center_freq1_idx = 0, center_freq2_idx = 0; @@ -260,10 +261,12 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ if (vht) bssid_info |= NEI_REP_BSSID_INFO_VHT; - if (he) - bssid_info |= NEI_REP_BSSID_INFO_HE; } + if (he) + bssid_info |= NEI_REP_BSSID_INFO_HE; + if (eht) + bssid_info |= NEI_REP_BSSID_INFO_EHT; /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ if (ieee80211_freq_to_channel_ext(hapd->iface->freq, diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index ccd1ed93..c5419261 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -358,6 +358,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) os_free(sta->vht_operation); os_free(sta->he_capab); os_free(sta->he_6ghz_capab); + os_free(sta->eht_capab); hostapd_free_psk_list(sta->psk); os_free(sta->identity); os_free(sta->radius_cui); @@ -410,6 +411,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) #ifdef CONFIG_TESTING_OPTIONS os_free(sta->sae_postponed_commit); + forced_memzero(sta->last_tk, WPA_TK_MAX_LEN); #endif /* CONFIG_TESTING_OPTIONS */ os_free(sta); @@ -1251,8 +1253,6 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, for (psk = ssid->wpa_psk; psk; psk = psk->next) if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0) break; - if (!psk) - return NULL; if (!psk || !psk->keyid[0]) return NULL; @@ -1461,7 +1461,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) 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%s%s", + "%s%s%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]" : ""), @@ -1481,6 +1481,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) (flags & WLAN_STA_HT ? "[HT]" : ""), (flags & WLAN_STA_VHT ? "[VHT]" : ""), (flags & WLAN_STA_HE ? "[HE]" : ""), + (flags & WLAN_STA_EHT ? "[EHT]" : ""), (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""), (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), (flags & WLAN_STA_WNM_SLEEP_MODE ? @@ -1553,7 +1554,7 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) if (hostapd_sta_add(hapd, sta->addr, 0, 0, sta->supported_rates, sta->supported_rates_len, - 0, NULL, NULL, NULL, 0, NULL, + 0, NULL, NULL, NULL, 0, NULL, 0, NULL, sta->flags, 0, 0, 0, 0)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 27e72f9a..af8f171b 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -42,6 +42,7 @@ #define WLAN_STA_HE BIT(24) #define WLAN_STA_6GHZ BIT(25) #define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26) +#define WLAN_STA_EHT BIT(27) #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) @@ -213,6 +214,8 @@ struct sta_info { struct ieee80211_he_capabilities *he_capab; size_t he_capab_len; struct ieee80211_he_6ghz_band_cap *he_6ghz_capab; + struct ieee80211_eht_capabilities *eht_capab; + size_t eht_capab_len; int sa_query_count; /* number of pending SA Query requests; * 0 = no SA Query in progress */ diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 0042ed6a..23a352c9 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -409,6 +409,8 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, u8 dialog_token, reason; const u8 *pos, *end; int enabled = hapd->conf->bss_transition; + char *hex = NULL; + size_t hex_len; #ifdef CONFIG_MBO if (hapd->conf->mbo_enabled) @@ -441,6 +443,17 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", pos, end - pos); + hex_len = 2 * (end - pos) + 1; + if (hex_len > 1) { + hex = os_malloc(hex_len); + if (hex) + wpa_snprintf_hex(hex, hex_len, pos, end - pos); + } + wpa_msg(hapd->msg_ctx, MSG_INFO, + BSS_TM_QUERY MACSTR " reason=%u%s%s", + MAC2STR(addr), reason, hex ? " neighbor=" : "", hex); + os_free(hex); + ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token); } diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index bb7ee254..ad918839 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -1,6 +1,6 @@ /* * IEEE 802.11 RSN / WPA Authenticator - * Copyright (c) 2004-2019, Jouni Malinen + * Copyright (c) 2004-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -607,7 +607,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth) while (group) { prev = group; group = group->next; - os_free(prev); + bin_clear_free(prev, sizeof(*prev)); } os_free(wpa_auth); @@ -1485,6 +1485,12 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx) struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_state_machine *sm = timeout_ctx; + if (sm->waiting_radius_psk) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + "Ignore EAPOL-Key timeout while waiting for RADIUS PSK"); + return; + } + sm->pending_1_of_4_timeout = 0; wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout"); sm->TimeoutEvt = true; @@ -1646,7 +1652,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, (key_data_len - 8) / 8, buf, key_data)) { os_free(hdr); - os_free(buf); + bin_clear_free(buf, key_data_len); return; } WPA_PUT_BE16(key_mic + mic_len, key_data_len); @@ -1667,10 +1673,10 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_NO_RC4 */ } else { os_free(hdr); - os_free(buf); + bin_clear_free(buf, key_data_len); return; } - os_free(buf); + bin_clear_free(buf, key_data_len); } if (key_info & WPA_KEY_INFO_MIC) { @@ -1823,9 +1829,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) case WPA_DEAUTH: case WPA_DISASSOC: sm->DeauthenticationRequest = true; -#ifdef CONFIG_IEEE80211R_AP os_memset(sm->PMK, 0, sizeof(sm->PMK)); sm->pmk_len = 0; +#ifdef CONFIG_IEEE80211R_AP os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); sm->xxkey_len = 0; os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1)); @@ -1853,6 +1859,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) break; } + if (sm->ptkstart_without_success > 3) { + wpa_printf(MSG_INFO, + "WPA: Multiple EAP reauth attempts without 4-way handshake completion, disconnect " + MACSTR, MAC2STR(sm->addr)); + sm->Disconnect = true; + break; + } + if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { wpa_printf(MSG_INFO, @@ -2195,6 +2209,7 @@ SM_STATE(WPA_PTK, PTKSTART) sm->PTKRequest = false; sm->TimeoutEvt = false; sm->alt_snonce_valid = false; + sm->ptkstart_without_success++; sm->TimeoutCtr++; if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) { @@ -3026,6 +3041,19 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) break; } + if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) && + wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk && + !sm->waiting_radius_psk) { + wpa_printf(MSG_DEBUG, "No PSK available - ask RADIUS server"); + wpa_auth->cb->request_radius_psk(wpa_auth->cb_ctx, sm->addr, + sm->wpa_key_mgmt, + sm->ANonce, + sm->last_rx_eapol_key, + sm->last_rx_eapol_key_len); + sm->waiting_radius_psk = 1; + return; + } + if (!ok) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "invalid MIC in msg 2/4 of 4-Way Handshake"); @@ -3279,6 +3307,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len, NULL, 0); + forced_memzero(&igtk, sizeof(igtk)); if (!conf->beacon_prot) return pos; @@ -3302,6 +3331,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK, (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len, NULL, 0); + forced_memzero(&bigtk, sizeof(bigtk)); return pos; } @@ -3382,7 +3412,7 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid, SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32]; - size_t gtk_len, kde_len, wpa_ie_len; + size_t gtk_len, kde_len = 0, wpa_ie_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; int secure, gtkidx, encr = 0; @@ -3640,7 +3670,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) WPA_KEY_INFO_KEY_TYPE, _rsc, sm->ANonce, kde, pos - kde, 0, encr); done: - os_free(kde); + bin_clear_free(kde, kde_len); os_free(wpa_ie_buf); os_free(wpa_ie_buf2); } @@ -3709,6 +3739,8 @@ SM_STATE(WPA_PTK, PTKINITDONE) #ifdef CONFIG_IEEE80211R_AP wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr); #endif /* CONFIG_IEEE80211R_AP */ + + sm->ptkstart_without_success = 0; } @@ -3783,6 +3815,11 @@ SM_STEP(WPA_PTK) } else if (wpa_auth_uses_sae(sm) && sm->pmksa) { SM_ENTER(WPA_PTK, PTKSTART); #endif /* CONFIG_SAE */ + } else if (wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) && + wpa_auth->conf.radius_psk) { + wpa_printf(MSG_DEBUG, + "INITPSK: No PSK yet available for STA - use RADIUS later"); + SM_ENTER(WPA_PTK, PTKSTART); } else { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "no PSK configured for the STA"); @@ -3861,7 +3898,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) struct wpa_group *gsm = sm->group; const u8 *kde; u8 *kde_buf = NULL, *pos, hdr[2]; - size_t kde_len; + size_t kde_len = 0; u8 *gtk, stub_gtk[32]; struct wpa_auth_config *conf = &sm->wpa_auth->conf; @@ -3930,7 +3967,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), rsc, NULL, kde, kde_len, gsm->GN, 1); - os_free(kde_buf); + bin_clear_free(kde_buf, kde_len); } @@ -5572,7 +5609,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_KEY_TYPE, _rsc, sm->ANonce, kde, pos - kde, 0, encr); - os_free(kde); + bin_clear_free(kde, kde_len); return 0; } @@ -5640,7 +5677,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), rsc, NULL, kde, kde_len, gsm->GN, 1); - os_free(kde_buf); + bin_clear_free(kde_buf, kde_len); return 0; } @@ -5711,3 +5748,28 @@ void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_TESTING_OPTIONS */ + + +void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success) +{ + if (!sm->waiting_radius_psk) { + wpa_printf(MSG_DEBUG, + "Ignore RADIUS PSK response for " MACSTR + " that did not wait one", + MAC2STR(sm->addr)); + return; + } + + wpa_printf(MSG_DEBUG, "RADIUS PSK response for " MACSTR " (%s)", + MAC2STR(sm->addr), success ? "success" : "fail"); + sm->waiting_radius_psk = 0; + + if (success) { + /* Try to process the EAPOL-Key msg 2/4 again */ + sm->EAPOLKeyReceived = true; + } else { + sm->Disconnect = true; + } + + eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL); +} diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 8f0b5a79..348a1def 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -1,6 +1,6 @@ /* * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2017, Jouni Malinen + * Copyright (c) 2004-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -275,6 +275,8 @@ struct wpa_auth_config { * PTK derivation regardless of advertised capabilities. */ bool force_kdk_derivation; + + bool radius_psk; }; typedef enum { @@ -322,6 +324,9 @@ struct wpa_auth_callbacks { void (*store_ptksa)(void *ctx, const u8 *addr, int cipher, u32 life_time, const struct wpa_ptk *ptk); void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher); + void (*request_radius_psk)(void *ctx, const u8 *addr, int key_mgmt, + const u8 *anonce, + const u8 *eapol, size_t eapol_len); #ifdef CONFIG_IEEE80211R_AP struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); int (*add_sta_ft)(void *ctx, const u8 *sta_addr); @@ -578,4 +583,6 @@ void wpa_auth_set_skip_send_eapol(struct wpa_authenticator *wpa_auth, void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth, u8 val); +void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success); + #endif /* WPA_AUTH_H */ diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index fef1104d..7a976135 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2240,6 +2240,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) wpa_printf(MSG_DEBUG, "FT: GTK subelem encryption failed: kek_len=%d", (int) kek_len); + forced_memzero(keybuf, sizeof(keybuf)); os_free(subelem); return NULL; } diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 9e88ea3d..9e8dae19 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -1,6 +1,6 @@ /* * hostapd / WPA authenticator glue code - * Copyright (c) 2002-2012, Jouni Malinen + * Copyright (c) 2002-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -29,6 +29,7 @@ #include "ap_drv_ops.h" #include "ap_config.h" #include "ieee802_11.h" +#include "ieee802_11_auth.h" #include "pmksa_cache_auth.h" #include "wpa_auth.h" #include "wpa_auth_glue.h" @@ -216,6 +217,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->force_kdk_derivation = conf->force_kdk_derivation; #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN */ + + wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS; } @@ -390,10 +393,14 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, psk = sta->psk->psk; for (pos = sta->psk; pos; pos = pos->next) { if (pos->is_passphrase) { - pbkdf2_sha1(pos->passphrase, - hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len, 4096, - pos->psk, PMK_LEN); + if (pbkdf2_sha1(pos->passphrase, + hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len, 4096, + pos->psk, PMK_LEN) != 0) { + wpa_printf(MSG_WARNING, + "Error in pbkdf2_sha1()"); + continue; + } pos->is_passphrase = 0; } if (pos->psk == prev_psk) { @@ -1445,6 +1452,23 @@ static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd) #endif /* CONFIG_IEEE80211R_AP */ +#ifndef CONFIG_NO_RADIUS +static void hostapd_request_radius_psk(void *ctx, const u8 *addr, int key_mgmt, + const u8 *anonce, + const u8 *eapol, size_t eapol_len) +{ + struct hostapd_data *hapd = ctx; + + wpa_printf(MSG_DEBUG, "RADIUS PSK request for " MACSTR " key_mgmt=0x%x", + MAC2STR(addr), key_mgmt); + wpa_hexdump(MSG_DEBUG, "ANonce", anonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "EAPOL", eapol, eapol_len); + hostapd_acl_req_radius_psk(hapd, addr, key_mgmt, anonce, eapol, + eapol_len); +} +#endif /* CONFIG_NO_RADIUS */ + + int hostapd_setup_wpa(struct hostapd_data *hapd) { struct wpa_auth_config _conf; @@ -1488,6 +1512,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) .set_session_timeout = hostapd_wpa_auth_set_session_timeout, .get_session_timeout = hostapd_wpa_auth_get_session_timeout, #endif /* CONFIG_IEEE80211R_AP */ +#ifndef CONFIG_NO_RADIUS + .request_radius_psk = hostapd_request_radius_psk, +#endif /* CONFIG_NO_RADIUS */ }; const u8 *wpa_ie; size_t wpa_ie_len; @@ -1633,4 +1660,10 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd) hapd->l2 = NULL; hostapd_wpa_unregister_ft_oui(hapd); #endif /* CONFIG_IEEE80211R_AP */ + +#ifdef CONFIG_TESTING_OPTIONS + forced_memzero(hapd->last_gtk, WPA_GTK_MAX_LEN); + forced_memzero(hapd->last_igtk, WPA_IGTK_MAX_LEN); + forced_memzero(hapd->last_bigtk, WPA_BIGTK_MAX_LEN); +#endif /* CONFIG_TESTING_OPTIONS */ } diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index a6dc1a59..17cb5a2e 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -89,6 +89,7 @@ struct wpa_state_machine { unsigned int rx_eapol_key_secure:1; unsigned int update_snonce:1; unsigned int alt_snonce_valid:1; + unsigned int waiting_radius_psk:1; #ifdef CONFIG_IEEE80211R_AP unsigned int ft_completed:1; unsigned int pmk_r1_name_valid:1; @@ -96,6 +97,8 @@ struct wpa_state_machine { unsigned int is_wnmsleep:1; unsigned int pmkid_set:1; + unsigned int ptkstart_without_success; + #ifdef CONFIG_OCV int ocv_enabled; #endif /* CONFIG_OCV */ diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c index 46d94b43..e2c4e109 100644 --- a/src/ap/wpa_auth_kay.c +++ b/src/ap/wpa_auth_kay.c @@ -138,7 +138,6 @@ static unsigned int conf_offset_val(enum confidentiality_offset co) switch (co) { case CONFIDENTIALITY_OFFSET_30: return 30; - break; case CONFIDENTIALITY_OFFSET_50: return 50; default: @@ -329,7 +328,9 @@ int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd, hapd->conf->macsec_replay_protect, hapd->conf->macsec_replay_window, hapd->conf->macsec_port, - hapd->conf->mka_priority, hapd->conf->iface, + hapd->conf->mka_priority, + hapd->conf->macsec_csindex, + hapd->conf->iface, hapd->own_addr); /* ieee802_1x_kay_init() frees kay_ctx on failure */ if (!res) diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 4f1c76b7..aacfa337 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -1069,10 +1069,11 @@ static void hostapd_free_wps(struct wps_context *wps) for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) wpabuf_free(wps->dev.vendor_ext[i]); wps_device_data_free(&wps->dev); - os_free(wps->network_key); + bin_clear_free(wps->network_key, wps->network_key_len); hostapd_wps_nfc_clear(wps); wpabuf_free(wps->dh_pubkey); wpabuf_free(wps->dh_privkey); + forced_memzero(wps->psk, sizeof(wps->psk)); os_free(wps); } diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h index d77b0076..c1f58077 100644 --- a/src/common/brcm_vendor.h +++ b/src/common/brcm_vendor.h @@ -40,15 +40,15 @@ * @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters. * Used for the case that FW handle SAE. * - * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters. + * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP parameters. * Used for the case that FW handle SAE. * * @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to * invoke the ACS function in device and pass selected channels to * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes. * - * @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list. - * Make sure it located at the end of the list. + * @BRCM_VENDOR_SCMD_MAX: This acts as a tail of cmds list. + * Make sure it is located at the end of the list. * */ enum brcm_nl80211_vendor_subcmds { @@ -67,7 +67,7 @@ enum brcm_nl80211_vendor_subcmds { }; /** - * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers + * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchronous event identifiers * * @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0 * diff --git a/src/common/dpp.c b/src/common/dpp.c index 42a93021..cc26b800 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -345,12 +345,36 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) } +static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi, + const char *txt) +{ + int val; + + if (!txt) + return 0; + + val = hex2num(txt[0]); + if (val < 0) + return -1; + bi->supported_curves = val; + + val = hex2num(txt[1]); + if (val > 0) + bi->supported_curves |= val << 4; + + wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x", + bi->supported_curves); + + return 0; +} + + static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) { const char *pos = uri; const char *end; const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL; - const char *version = NULL; + const char *version = NULL, *supported_curves = NULL; struct dpp_bootstrap_info *bi; wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri)); @@ -383,6 +407,8 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) pk = pos + 2; else if (pos[0] == 'V' && pos[1] == ':' && !version) version = pos + 2; + else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves) + supported_curves = pos + 2; else wpa_hexdump_ascii(MSG_DEBUG, "DPP: Ignore unrecognized URI parameter", @@ -404,6 +430,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) dpp_parse_uri_mac(bi, mac) < 0 || dpp_parse_uri_info(bi, info) < 0 || dpp_parse_uri_version(bi, version) < 0 || + dpp_parse_uri_supported_curves(bi, supported_curves) < 0 || dpp_parse_uri_pk(bi, pk) < 0) { dpp_bootstrap_info_free(bi); bi = NULL; @@ -604,6 +631,7 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) { char macstr[ETH_ALEN * 2 + 10]; size_t len; + char supp_curves[10]; len = 4; /* "DPP:" */ if (bi->chan) @@ -621,11 +649,26 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) #endif /* CONFIG_DPP2 */ len += 4 + os_strlen(bi->pk); /* K:...;; */ + if (bi->supported_curves) { + u8 val = bi->supported_curves; + + if (val & 0xf0) { + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + len += os_snprintf(supp_curves, sizeof(supp_curves), + "B:%02x;", val); + } else { + len += os_snprintf(supp_curves, sizeof(supp_curves), + "B:%x;", val); + } + } else { + supp_curves[0] = '\0'; + } + os_free(bi->uri); bi->uri = os_malloc(len + 1); if (!bi->uri) return -1; - os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;", + os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;", bi->chan ? "C:" : "", bi->chan ? bi->chan : "", bi->chan ? ";" : "", macstr, @@ -633,6 +676,7 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) bi->info ? ";" : "", DPP_VERSION == 3 ? "V:3;" : (DPP_VERSION == 2 ? "V:2;" : ""), + supp_curves, bi->pk); return 0; } @@ -658,9 +702,12 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, { size_t nonce_len; size_t json_len, clear_len; - struct wpabuf *clear = NULL, *msg = NULL; + struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL; u8 *wrapped; size_t attr_len; +#ifdef CONFIG_DPP3 + u8 auth_i[DPP_MAX_HASH_LEN]; +#endif /* CONFIG_DPP3 */ wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); @@ -675,6 +722,18 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, /* { E-nonce, configAttrib }ke */ clear_len = 4 + nonce_len + 4 + json_len; +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key) { + pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + if (!pe) + goto fail; + clear_len += 4 + wpabuf_len(pe); + + if (dpp_derive_auth_i(auth, auth_i) < 0) + goto fail; + clear_len += 4 + auth->curve->hash_len; + } +#endif /* CONFIG_DPP3 */ clear = wpabuf_alloc(clear_len); attr_len = 4 + clear_len + AES_BLOCK_SIZE; #ifdef CONFIG_TESTING_OPTIONS @@ -716,6 +775,21 @@ skip_e_nonce: } #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_DPP3 + if (pe) { + wpa_printf(MSG_DEBUG, "DPP: Pe"); + wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY); + wpabuf_put_le16(clear, wpabuf_len(pe)); + wpabuf_put_buf(clear, pe); + } + if (auth->waiting_new_key) { + wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag"); + wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); + wpabuf_put_le16(clear, auth->curve->hash_len); + wpabuf_put_data(clear, auth_i, auth->curve->hash_len); + } +#endif /* CONFIG_DPP3 */ + /* configAttrib */ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); wpabuf_put_le16(clear, json_len); @@ -748,13 +822,15 @@ skip_wrapped_data: wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Request frame attributes", msg); +out: wpabuf_free(clear); + wpabuf_free(pe); return msg; fail: - wpabuf_free(clear); wpabuf_free(msg); - return NULL; + msg = NULL; + goto out; } @@ -815,7 +891,7 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, size_t len, name_len; const char *tech = "infra"; const char *dpp_name; - struct wpabuf *buf, *json; + struct wpabuf *buf = NULL, *json = NULL; char *csr = NULL; #ifdef CONFIG_TESTING_OPTIONS @@ -840,19 +916,17 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, csr = base64_encode_no_lf(wpabuf_head(auth->csr), wpabuf_len(auth->csr), &csr_len); if (!csr) - return NULL; + goto fail; len += 30 + csr_len; } #endif /* CONFIG_DPP2 */ json = wpabuf_alloc(len); if (!json) - return NULL; + goto fail; json_start_object(json, NULL); - if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) { - wpabuf_free(json); - return NULL; - } + if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) + goto fail; json_value_sep(json); json_add_string(json, "wi-fi_tech", tech); json_value_sep(json); @@ -877,6 +951,7 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, json_end_object(json); buf = dpp_build_conf_req(auth, wpabuf_head(json)); +fail: wpabuf_free(json); os_free(csr); @@ -1431,7 +1506,8 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, struct wpabuf *buf = NULL; char *signed_conn = NULL; size_t tailroom; - const struct dpp_curve_params *curve; + const struct dpp_curve_params *curve; /* C-sign-key curve */ + const struct dpp_curve_params *nak_curve; /* netAccessKey curve */ struct wpabuf *dppcon = NULL; size_t extra_len = 1000; int incl_legacy; @@ -1444,6 +1520,10 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, goto fail; } curve = auth->conf->curve; + if (auth->new_curve && auth->new_key_received) + nak_curve = auth->new_curve; + else + nak_curve = auth->curve; akm = conf->akm; if (dpp_akm_ver2(akm) && auth->peer_version < 2) { @@ -1461,7 +1541,7 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, extra_len += os_strlen(conf->group_id); /* Connector (JSON dppCon object) */ - dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3); + dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3); if (!dppcon) goto fail; #ifdef CONFIG_TESTING_OPTIONS @@ -1491,9 +1571,31 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, #ifdef CONFIG_TESTING_OPTIONS skip_groups: #endif /* CONFIG_TESTING_OPTIONS */ - if (!auth->peer_protocol_key || - dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, - auth->curve) < 0) { + if (!auth->peer_protocol_key) { + wpa_printf(MSG_DEBUG, + "DPP: No peer protocol key available to build netAccessKey JWK"); + goto fail; + } +#ifdef CONFIG_DPP3 + if (auth->conf->net_access_key_curve && + auth->curve != auth->conf->net_access_key_curve && + !auth->new_key_received) { + wpa_printf(MSG_DEBUG, + "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s", + auth->curve->name, + auth->conf->net_access_key_curve->name, + auth->waiting_new_key ? + "the required key not received" : + "request a new key"); + if (auth->waiting_new_key) + auth->waiting_new_key = false; /* failed */ + else + auth->waiting_new_key = true; + goto fail; + } +#endif /* CONFIG_DPP3 */ + if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, + nak_curve) < 0) { wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); goto fail; } @@ -1605,6 +1707,20 @@ skip_groups: wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object", wpabuf_head(buf), wpabuf_len(buf)); +#ifdef CONFIG_DPP3 + if (!auth->conf->net_access_key_curve) { + /* All netAccessKey values used in the network will have to be + * from the same curve for network introduction to work, so + * hardcode the first used netAccessKey curve for consecutive + * operations if there was no explicit configuration of which + * curve to use. */ + wpa_printf(MSG_DEBUG, + "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning", + nak_curve->name); + auth->conf->net_access_key_curve = nak_curve; + } +#endif /* CONFIG_DPP3 */ + out: os_free(signed_conn); wpabuf_free(dppcon); @@ -1732,7 +1848,7 @@ struct wpabuf * dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req) { - struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL; + struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL; size_t clear_len, attr_len; struct wpabuf *clear = NULL, *msg = NULL; u8 *wrapped; @@ -1766,6 +1882,10 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta && auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr) status = DPP_STATUS_CSR_NEEDED; +#ifdef CONFIG_DPP3 + else if (auth->waiting_new_key) + status = DPP_STATUS_NEW_KEY_NEEDED; +#endif /* CONFIG_DPP3 */ else status = DPP_STATUS_CONFIGURE_FAILURE; forced_status: @@ -1785,6 +1905,31 @@ forced_status: if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta && auth->conf_sta->csrattrs) clear_len += 4 + os_strlen(auth->conf_sta->csrattrs); +#ifdef CONFIG_DPP3 + if (status == DPP_STATUS_NEW_KEY_NEEDED) { + struct crypto_ec_key *new_pc; + + clear_len += 6; /* Finite Cyclic Group attribute */ + + wpa_printf(MSG_DEBUG, + "DPP: Generate a new own protocol key for the curve %s", + auth->conf->net_access_key_curve->name); + new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve); + if (!new_pc) { + wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc"); + return NULL; + } + pc = crypto_ec_key_get_pubkey_point(new_pc, 0); + if (!pc) { + crypto_ec_key_deinit(new_pc); + return NULL; + } + crypto_ec_key_deinit(auth->own_protocol_key); + auth->own_protocol_key = new_pc; + auth->new_curve = auth->conf->net_access_key_curve; + clear_len += 4 + wpabuf_len(pc); + } +#endif /* CONFIG_DPP3 */ clear = wpabuf_alloc(clear_len); attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; #ifdef CONFIG_TESTING_OPTIONS @@ -1862,6 +2007,27 @@ skip_e_nonce: wpabuf_put_str(clear, auth->conf_sta->csrattrs); } +#ifdef CONFIG_DPP3 + if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf && + auth->conf->net_access_key_curve) { + u16 ike_group = auth->conf->net_access_key_curve->ike_group; + + /* Finite Cyclic Group attribute */ + wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u", + ike_group); + wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP); + wpabuf_put_le16(clear, 2); + wpabuf_put_le16(clear, ike_group); + + if (pc) { + wpa_printf(MSG_DEBUG, "DPP: Pc"); + wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY); + wpabuf_put_le16(clear, wpabuf_len(pc)); + wpabuf_put_buf(clear, pc); + } + } +#endif /* CONFIG_DPP3 */ + #ifdef CONFIG_TESTING_OPTIONS skip_config_obj: if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) { @@ -1912,6 +2078,7 @@ out: wpabuf_clear_free(conf2); wpabuf_clear_free(env_data); wpabuf_clear_free(clear); + wpabuf_free(pc); return msg; fail: @@ -1933,6 +2100,10 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, struct json_token *root = NULL, *token; enum dpp_netrole netrole; struct wpabuf *cert_req = NULL; +#ifdef CONFIG_DPP3 + const u8 *i_proto; + u16 i_proto_len; +#endif /* CONFIG_DPP3 */ #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) { @@ -1986,6 +2157,59 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); +#ifdef CONFIG_DPP3 + i_proto = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len); + if (i_proto && !auth->waiting_new_key) { + dpp_auth_fail(auth, + "Enrollee included a new protocol key even though one was not expected"); + goto fail; + } + if (i_proto) { + struct crypto_ec_key *pe; + u8 auth_i[DPP_MAX_HASH_LEN]; + const u8 *rx_auth_i; + u16 rx_auth_i_len; + + wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)", + i_proto, i_proto_len); + + pe = dpp_set_pubkey_point(auth->own_protocol_key, + i_proto, i_proto_len); + if (!pe) { + dpp_auth_fail(auth, + "Invalid Initiator Protocol Key (Pe)"); + goto fail; + } + dpp_debug_print_key("New Peer Protocol Key (Pe)", pe); + crypto_ec_key_deinit(auth->peer_protocol_key); + auth->peer_protocol_key = pe; + auth->new_key_received = true; + auth->waiting_new_key = false; + + if (dpp_derive_auth_i(auth, auth_i) < 0) + goto fail; + + rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len); + if (!rx_auth_i) { + dpp_auth_fail(auth, + "Missing Initiator Authentication Tag"); + goto fail; + } + if (rx_auth_i_len != auth->curve->hash_len || + os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) { + dpp_auth_fail(auth, + "Mismatch in Initiator Authenticating Tag"); + wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I", + rx_auth_i, rx_auth_i_len); + wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'", + auth_i, auth->curve->hash_len); + goto fail; + } + } +#endif /* CONFIG_DPP3 */ + config_attr = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_ATTR_OBJ, &config_attr_len); @@ -2989,6 +3213,72 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, goto fail; } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) { + const u8 *fcgroup, *r_proto; + u16 fcgroup_len, r_proto_len; + u16 group; + const struct dpp_curve_params *curve; + struct crypto_ec_key *new_pe; + struct crypto_ec_key *pc; + + fcgroup = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_FINITE_CYCLIC_GROUP, + &fcgroup_len); + if (!fcgroup || fcgroup_len != 2) { + dpp_auth_fail(auth, + "Missing or invalid required Finite Cyclic Group attribute"); + goto fail; + } + group = WPA_GET_LE16(fcgroup); + + wpa_printf(MSG_DEBUG, + "DPP: Configurator requested a new protocol key from group %u", + group); + curve = dpp_get_curve_ike_group(group); + if (!curve) { + dpp_auth_fail(auth, + "Unsupported group for new protocol key"); + goto fail; + } + + new_pe = dpp_gen_keypair(curve); + if (!new_pe) { + dpp_auth_fail(auth, + "Failed to generate a new protocol key"); + goto fail; + } + + crypto_ec_key_deinit(auth->own_protocol_key); + auth->own_protocol_key = new_pe; + auth->new_curve = curve; + + r_proto = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_R_PROTOCOL_KEY, + &r_proto_len); + if (!r_proto) { + dpp_auth_fail(auth, + "Missing required Responder Protocol Key attribute (Pc)"); + goto fail; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)", + r_proto, r_proto_len); + + pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len); + if (!pc) { + dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)"); + goto fail; + } + dpp_debug_print_key("New Peer Protocol Key (Pc)", pc); + + crypto_ec_key_deinit(auth->peer_protocol_key); + auth->peer_protocol_key = pc; + + auth->waiting_new_key = true; + ret = -3; + goto fail; + } +#endif /* CONFIG_DPP3 */ if (status[0] != DPP_STATUS_OK) { dpp_auth_fail(auth, "Configurator rejected configuration"); goto fail; @@ -3903,10 +4193,47 @@ struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, } +static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi, + char *txt) +{ + char *token, *context = NULL; + u8 curves = 0; + + if (!txt) + return 0; + + while ((token = str_token(txt, ":", &context))) { + if (os_strcmp(token, "P-256") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256); + } else if (os_strcmp(token, "P-384") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384); + } else if (os_strcmp(token, "P-521") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521); + } else if (os_strcmp(token, "BP-256") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256); + } else if (os_strcmp(token, "BP-384") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384); + } else if (os_strcmp(token, "BP-512") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512); + } else { + wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'", + token); + return -1; + } + } + bi->supported_curves = curves; + + wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x", + bi->supported_curves); + + return 0; +} + + int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) { char *mac = NULL, *info = NULL, *curve = NULL; - char *key = NULL; + char *key = NULL, *supported_curves = NULL; u8 *privkey = NULL; size_t privkey_len = 0; int ret = -1; @@ -3933,6 +4260,7 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) info = get_param(cmd, " info="); curve = get_param(cmd, " curve="); key = get_param(cmd, " key="); + supported_curves = get_param(cmd, " supported_curves="); if (key) { privkey_len = os_strlen(key) / 2; @@ -3946,6 +4274,7 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) dpp_parse_uri_chan_list(bi, bi->chan) < 0 || dpp_parse_uri_mac(bi, mac) < 0 || dpp_parse_uri_info(bi, info) < 0 || + dpp_parse_supported_curves_list(bi, supported_curves) < 0 || dpp_gen_uri(bi) < 0) goto fail; @@ -3958,6 +4287,7 @@ fail: os_free(mac); os_free(info); str_clear_free(key); + os_free(supported_curves); bin_clear_free(privkey, privkey_len); dpp_bootstrap_info_free(bi); return ret; @@ -4012,12 +4342,43 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, { struct dpp_bootstrap_info *bi; char pkhash[2 * SHA256_MAC_LEN + 1]; + char supp_curves[100]; bi = dpp_bootstrap_get_id(dpp, id); if (!bi) return -1; wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash, SHA256_MAC_LEN); + + supp_curves[0] = '\0'; + if (bi->supported_curves) { + int ret; + size_t i; + char *pos = supp_curves; + char *end = &supp_curves[sizeof(supp_curves)]; + const char *curve[6] = { "P-256", "P-384", "P-521", + "BP-256", "BP-384", "BP-512" }; + + ret = os_snprintf(pos, end - pos, "supp_curves="); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + + for (i = 0; i < ARRAY_SIZE(curve); i++) { + if (!(bi->supported_curves & BIT(i))) + continue; + ret = os_snprintf(pos, end - pos, "%s:", curve[i]); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (pos[-1] == ':') + pos[-1] = '\n'; + else + supp_curves[0] = '\0'; + } + return os_snprintf(reply, reply_size, "type=%s\n" "mac_addr=" MACSTR "\n" "info=%s\n" @@ -4025,7 +4386,7 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, "use_freq=%u\n" "curve=%s\n" "pkhash=%s\n" - "version=%d\n", + "version=%d\n%s", dpp_bootstrap_type_txt(bi->type), MAC2STR(bi->mac_addr), bi->info ? bi->info : "", @@ -4033,7 +4394,8 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, bi->num_freq == 1 ? bi->freq[0] : 0, bi->curve->name, pkhash, - bi->version); + bi->version, + supp_curves); } @@ -4210,12 +4572,25 @@ static unsigned int dpp_next_configurator_id(struct dpp_global *dpp) int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) { - char *curve = NULL; + char *curve; char *key = NULL, *ppkey = NULL; u8 *privkey = NULL, *pp_key = NULL; size_t privkey_len = 0, pp_key_len = 0; int ret = -1; struct dpp_configurator *conf = NULL; + const struct dpp_curve_params *net_access_key_curve = NULL; + + curve = get_param(cmd, " net_access_key_curve="); + if (curve) { + net_access_key_curve = dpp_get_curve_name(curve); + if (!net_access_key_curve) { + wpa_printf(MSG_DEBUG, + "DPP: Unsupported net_access_key_curve: %s", + curve); + goto fail; + } + os_free(curve); + } curve = get_param(cmd, " curve="); key = get_param(cmd, " key="); @@ -4242,6 +4617,7 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) if (!conf) goto fail; + conf->net_access_key_curve = net_access_key_curve; conf->id = dpp_next_configurator_id(dpp); dl_list_add(&dpp->configurator, &conf->list); ret = conf->id; @@ -4257,6 +4633,32 @@ fail: } +int dpp_configurator_set(struct dpp_global *dpp, const char *cmd) +{ + unsigned int id; + struct dpp_configurator *conf; + char *curve; + + id = atoi(cmd); + conf = dpp_configurator_get_id(dpp, id); + if (!conf) + return -1; + + curve = get_param(cmd, " net_access_key_curve="); + if (curve) { + const struct dpp_curve_params *net_access_key_curve; + + net_access_key_curve = dpp_get_curve_name(curve); + os_free(curve); + if (!net_access_key_curve) + return -1; + conf->net_access_key_curve = net_access_key_curve; + } + + return 0; +} + + static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id) { struct dpp_configurator *conf, *tmp; diff --git a/src/common/dpp.h b/src/common/dpp.h index 2f85ebd7..fba41190 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -110,6 +110,7 @@ enum dpp_status_error { DPP_STATUS_CONFIGURE_PENDING = 11, DPP_STATUS_CSR_NEEDED = 12, DPP_STATUS_CSR_BAD = 13, + DPP_STATUS_NEW_KEY_NEEDED = 14, }; /* DPP Reconfig Flags object - connectorKey values */ @@ -145,6 +146,15 @@ enum dpp_bootstrap_type { DPP_BOOTSTRAP_NFC_URI, }; +enum dpp_bootstrap_supported_curves { + DPP_BOOTSTRAP_CURVE_P_256 = 0, + DPP_BOOTSTRAP_CURVE_P_384 = 1, + DPP_BOOTSTRAP_CURVE_P_521 = 2, + DPP_BOOTSTRAP_CURVE_BP_256 = 3, + DPP_BOOTSTRAP_CURVE_BP_384 = 4, + DPP_BOOTSTRAP_CURVE_BP_512 = 5, +}; + struct dpp_bootstrap_info { struct dl_list list; unsigned int id; @@ -158,6 +168,7 @@ struct dpp_bootstrap_info { unsigned int num_freq; bool channels_listed; u8 version; + u8 supported_curves; /* enum dpp_bootstrap_supported_curves bitmap */ int own; struct crypto_ec_key *pubkey; u8 pubkey_hash[SHA256_MAC_LEN]; @@ -172,6 +183,12 @@ struct dpp_bootstrap_info { #define PKEX_COUNTER_T_LIMIT 5 +enum dpp_pkex_ver { + PKEX_VER_AUTO, + PKEX_VER_ONLY_1, + PKEX_VER_ONLY_2, +}; + struct dpp_pkex { void *msg_ctx; unsigned int initiator:1; @@ -253,6 +270,7 @@ struct dpp_authentication { void *msg_ctx; u8 peer_version; const struct dpp_curve_params *curve; + const struct dpp_curve_params *new_curve; struct dpp_bootstrap_info *peer_bi; struct dpp_bootstrap_info *own_bi; struct dpp_bootstrap_info *tmp_own_bi; @@ -353,6 +371,8 @@ struct dpp_authentication { char *trusted_eap_server_name; struct wpabuf *cacert; struct wpabuf *certbag; + bool waiting_new_key; + bool new_key_received; void *config_resp_ctx; void *gas_server_ctx; bool use_config_query; @@ -378,6 +398,7 @@ struct dpp_configurator { u8 kid_hash[SHA256_MAC_LEN]; char *kid; const struct dpp_curve_params *curve; + const struct dpp_curve_params *net_access_key_curve; char *connector; /* own Connector for reconfiguration */ struct crypto_ec_key *connector_key; struct crypto_ec_key *pp_key; @@ -512,6 +533,8 @@ enum dpp_test_behavior { DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93, DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ = 94, DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP = 95, + DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 96, + DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 97, }; extern enum dpp_test_behavior dpp_test; @@ -681,6 +704,7 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp, const u8 *hash); int dpp_configurator_add(struct dpp_global *dpp, const char *cmd); +int dpp_configurator_set(struct dpp_global *dpp, const char *cmd); int dpp_configurator_remove(struct dpp_global *dpp, const char *id); int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, char *buf, size_t buflen); @@ -698,6 +722,8 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, size_t data_len); int dpp_controller_start(struct dpp_global *dpp, struct dpp_controller_config *config); +int dpp_controller_set_params(struct dpp_global *dpp, + const char *configurator_params); void dpp_controller_stop(struct dpp_global *dpp); void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx); struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp, diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c index 4fac7de8..47f56c25 100644 --- a/src/common/dpp_crypto.c +++ b/src/common/dpp_crypto.c @@ -2355,6 +2355,97 @@ fail: #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 +int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i) +{ + int ret = -1, res; + u8 Sx[DPP_MAX_SHARED_SECRET_LEN]; + size_t Sx_len; + unsigned int hash_len; + const char *info = "New DPP Protocol Key"; + const u8 *addr[3]; + size_t len[3]; + u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN]; + struct wpabuf *pcx = NULL, *pex = NULL; + + hash_len = auth->curve->hash_len; + + /* + * Configurator: S = pc * Pe + * Enrollee: S = pe * Pc + * k = HKDF(bk, "New DPP Protocol Key", S.x) + * = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key", + * len(new-curve-hash-out)) + * Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) + * + * auth->own_protocol_key and auth->peer_protocol_key have already been + * updated to use the new keys. The new curve determines the size of + * the (new) protocol keys and S.x. The other parameters (bk, hash + * algorithm, k) are determined based on the initially determined curve + * during the (re)authentication exchange. + */ + + if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key, + Sx, &Sx_len) < 0) + goto fail; + + wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len); + + /* tmp = HKDF-Extract(bk, S.x) */ + addr[0] = Sx; + len[0] = Sx_len; + res = dpp_hmac_vector(hash_len, auth->bk, hash_len, 1, addr, len, tmp); + if (res < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)", + tmp, hash_len); + /* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(hash-output)) + */ + res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, + "DPP: k = HKDF-Expand(\"New DPP Protocol Key\")", + k, hash_len); + + /* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) */ + addr[0] = auth->e_nonce; + len[0] = auth->curve->nonce_len; + + if (auth->configurator) { + pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key, + 0); + } else { + pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key, + 0); + pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + } + if (!pcx || !pex) + goto fail; + addr[1] = wpabuf_head(pcx); + len[1] = wpabuf_len(pcx) / 2; + addr[2] = wpabuf_head(pex); + len[2] = wpabuf_len(pex) / 2; + + if (dpp_hmac_vector(hash_len, k, hash_len, 3, addr, len, auth_i) < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, + "DPP: Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)", + auth_i, hash_len); + ret = 0; +fail: + forced_memzero(Sx, sizeof(Sx)); + forced_memzero(tmp, sizeof(tmp)); + forced_memzero(k, sizeof(k)); + wpabuf_free(pcx); + wpabuf_free(pex); + return ret; +} +#endif /* CONFIG_DPP3 */ + + #ifdef CONFIG_TESTING_OPTIONS int dpp_test_gen_invalid_key(struct wpabuf *msg, diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h index 0f31ae56..10db4e81 100644 --- a/src/common/dpp_i.h +++ b/src/common/dpp_i.h @@ -136,6 +136,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth, struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey, struct crypto_ec_key *a_nonce, struct crypto_ec_key *e_prime_id); +int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i); char * dpp_sign_connector(struct dpp_configurator *conf, const struct wpabuf *dppcon); int dpp_test_gen_invalid_key(struct wpabuf *msg, diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c index 7137bc5f..452c5024 100644 --- a/src/common/dpp_reconfig.c +++ b/src/common/dpp_reconfig.c @@ -131,6 +131,7 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) { struct wpabuf *msg; size_t attr_len; + u8 ver = DPP_VERSION; /* Build DPP Reconfig Authentication Request frame attributes */ attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) + @@ -144,10 +145,25 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) wpabuf_put_le16(msg, 1); wpabuf_put_u8(msg, auth->transaction_id); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version"); + goto skip_proto_ver; + } + if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version"); + ver = 1; + } +#endif /* CONFIG_TESTING_OPTIONS */ + /* Protocol Version */ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); wpabuf_put_le16(msg, 1); - wpabuf_put_u8(msg, DPP_VERSION); + wpabuf_put_u8(msg, ver); + +#ifdef CONFIG_TESTING_OPTIONS +skip_proto_ver: +#endif /* CONFIG_TESTING_OPTIONS */ /* DPP Connector */ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c index e88c6de6..c83fb2da 100644 --- a/src/common/dpp_tcp.c +++ b/src/common/dpp_tcp.c @@ -89,6 +89,9 @@ static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx); static void dpp_controller_auth_success(struct dpp_connection *conn, int initiator); static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx); +#ifdef CONFIG_DPP3 +static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx); +#endif /* CONFIG_DPP3 */ static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx); static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx); @@ -107,6 +110,9 @@ static void dpp_connection_free(struct dpp_connection *conn) eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL); eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL); eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL); +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(dpp_tcp_build_new_key, conn, NULL); +#endif /* CONFIG_DPP3 */ wpabuf_free(conn->msg); wpabuf_free(conn->msg_out); dpp_auth_deinit(conn->auth); @@ -193,6 +199,14 @@ static void dpp_controller_gas_done(struct dpp_connection *conn) return; } +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + conn->on_tcp_tx_complete_gas_done = 0; + return; + } +#endif /* CONFIG_DPP3 */ + if (auth->peer_version >= 2 && auth->conf_resp_status == DPP_STATUS_OK) { wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); @@ -999,7 +1013,7 @@ static int dpp_controller_rx_pkex_exchange_req(struct dpp_connection *conn, return 0; } - conn->pkex = dpp_pkex_rx_exchange_req(conn->ctrl->global, ctrl->pkex_bi, + conn->pkex = dpp_pkex_rx_exchange_req(conn->msg_ctx, ctrl->pkex_bi, NULL, NULL, ctrl->pkex_identifier, ctrl->pkex_code, @@ -1440,6 +1454,21 @@ static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx) } +#ifdef CONFIG_DPP3 +static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx) +{ + struct dpp_connection *conn = eloop_ctx; + struct dpp_authentication *auth = conn->auth; + + if (!auth || !auth->waiting_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + dpp_controller_start_gas_client(conn); +} +#endif /* CONFIG_DPP3 */ + + static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) { struct dpp_authentication *auth = conn->auth; @@ -1460,6 +1489,14 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL); return 0; } +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, dpp_tcp_build_new_key, conn, + NULL); + return 0; + } +#endif /* CONFIG_DPP3 */ if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); return -1; @@ -2047,6 +2084,29 @@ fail: } +int dpp_controller_set_params(struct dpp_global *dpp, + const char *configurator_params) +{ + + if (!dpp || !dpp->controller) + return -1; + + if (configurator_params) { + char *val = os_strdup(configurator_params); + + if (!val) + return -1; + os_free(dpp->controller->configurator_params); + dpp->controller->configurator_params = val; + } else { + os_free(dpp->controller->configurator_params); + dpp->controller->configurator_params = NULL; + } + + return 0; +} + + void dpp_controller_stop(struct dpp_global *dpp) { if (dpp) { @@ -2183,6 +2243,9 @@ bool dpp_tcp_conn_status_requested(struct dpp_global *dpp) { struct dpp_connection *conn; + if (!dpp) + return false; + dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { if (conn->auth && conn->auth->conn_status_requested) return true; diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index f168d4e9..732124f4 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -383,10 +383,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, int freq, int channel, int enable_edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, int he_enabled, - int sec_channel_offset, + bool eht_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1, u32 vht_caps, - struct he_capabilities *he_cap) + struct he_capabilities *he_cap, + struct eht_capabilities *eht_cap) { if (!he_cap || !he_cap->he_supported) he_enabled = 0; @@ -397,6 +398,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, data->ht_enabled = ht_enabled; data->vht_enabled = vht_enabled; data->he_enabled = he_enabled; + data->eht_enabled = eht_enabled; data->sec_channel_offset = sec_channel_offset; data->center_freq1 = freq + sec_channel_offset * 10; data->center_freq2 = 0; @@ -415,9 +417,9 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, &data->edmg); if (is_6ghz_freq(freq)) { - if (!data->he_enabled) { + if (!data->he_enabled && !data->eht_enabled) { wpa_printf(MSG_ERROR, - "Can't set 6 GHz mode - HE isn't enabled"); + "Can't set 6 GHz mode - HE or EHT aren't enabled"); return -1; } @@ -480,7 +482,20 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return 0; } - if (data->he_enabled) switch (oper_chwidth) { +#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */ + if (data->eht_enabled) switch (oper_chwidth) { + case CHANWIDTH_320MHZ: + if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & + EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) { + wpa_printf(MSG_ERROR, + "320 MHz channel width is not supported in 5 or 6 GHz"); + return -1; + } + break; + } +#endif + + if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) { case CHANWIDTH_USE_HT: if (sec_channel_offset == 0) break; @@ -543,7 +558,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, break; } - if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) { + if (data->eht_enabled || data->he_enabled || + data->vht_enabled) switch (oper_chwidth) { case CHANWIDTH_USE_HT: if (center_segment1 || (center_segment0 != 0 && diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h index 0e92aa0f..d87a2caf 100644 --- a/src/common/hw_features_common.h +++ b/src/common/hw_features_common.h @@ -40,10 +40,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, int freq, int channel, int edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, int he_enabled, - int sec_channel_offset, + bool eht_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1, u32 vht_caps, - struct he_capabilities *he_caps); + struct he_capabilities *he_caps, + struct eht_capabilities *eht_cap); void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps, int disabled); int ieee80211ac_cap_check(u32 hw, u32 conf); diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index adc6f59a..44335de8 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -311,6 +311,14 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->pasn_params = pos; elems->pasn_params_len = elen; break; + case WLAN_EID_EXT_EHT_CAPABILITIES: + elems->eht_capabilities = pos; + elems->eht_capabilities_len = elen; + break; + case WLAN_EID_EXT_EHT_OPERATION: + elems->eht_operation = pos; + elems->eht_operation_len = elen; + break; default: if (show_errors) { wpa_printf(MSG_MSGDUMP, @@ -1902,7 +1910,7 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP }, /* - * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center + * IEEE Std 802.11ax-2021, Table E-4 actually talks about channel center * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing * of 80 MHz, but currently use the following definition for simplicity * (these center frequencies are not actual channels, which makes diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index ec6556f6..e21f7be6 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -117,6 +117,8 @@ struct ieee802_11_elems { const u8 *sae_pk; const u8 *s1g_capab; const u8 *pasn_params; + const u8 *eht_capabilities; + const u8 *eht_operation; u8 ssid_len; u8 supp_rates_len; @@ -171,6 +173,8 @@ struct ieee802_11_elems { u8 short_ssid_list_len; u8 sae_pk_len; u8 pasn_params_len; + u8 eht_capabilities_len; + u8 eht_operation_len; struct mb_ies_info mb_ies; struct frag_ies_info frag_ies; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 4300ae54..c341a1d5 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -479,6 +479,7 @@ #define WLAN_EID_EXT_HE_OPERATION 36 #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38 #define WLAN_EID_EXT_SPATIAL_REUSE 39 +#define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42 #define WLAN_EID_EXT_OCV_OCI 54 #define WLAN_EID_EXT_SHORT_SSID_LIST 58 #define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59 @@ -489,6 +490,11 @@ #define WLAN_EID_EXT_REJECTED_GROUPS 92 #define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93 #define WLAN_EID_EXT_PASN_PARAMS 100 +#define WLAN_EID_EXT_EHT_OPERATION 106 +#define WLAN_EID_EXT_MULTI_LINK 107 +#define WLAN_EID_EXT_EHT_CAPABILITIES 108 +#define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109 +#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110 /* Extended Capabilities field */ #define WLAN_EXT_CAPAB_20_40_COEX 0 @@ -1953,6 +1959,26 @@ struct tpc_report { u8 link_margin; } STRUCT_PACKED; +/* + * IEEE Std 802.11ax-2021, Table 9-275a - Maximum Transmit Power + * Interpretation subfield encoding + */ +enum max_tx_pwr_interpretation { + LOCAL_EIRP = 0, + LOCAL_EIRP_PSD = 1, + REGULATORY_CLIENT_EIRP = 2, + REGULATORY_CLIENT_EIRP_PSD = 3, +}; + +/* + * IEEE Std 802.11ax-2021, Table E-13 - Maximum Transmit Power + * Category subfield encoding in the United States + */ +enum reg_6g_client_type { + REG_DEFAULT_CLIENT = 0, + REG_SUBORDINATE_CLIENT = 1, +}; + #define RRM_CAPABILITIES_IE_LEN 5 /* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */ @@ -2173,6 +2199,7 @@ enum phy_type { #define NEI_REP_BSSID_INFO_VHT BIT(12) #define NEI_REP_BSSID_INFO_FTM BIT(13) #define NEI_REP_BSSID_INFO_HE BIT(14) +#define NEI_REP_BSSID_INFO_EHT BIT(21) /* * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information @@ -2209,7 +2236,7 @@ struct ieee80211_he_operation { * Operation Information subfield (5 octets). */ } STRUCT_PACKED; -/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */ +/* IEEE Std 802.11ax-2021, Figure 9-788k - 6 GHz Operation Information field */ struct ieee80211_he_6ghz_oper_info { u8 primary_chan; u8 control; @@ -2218,15 +2245,22 @@ struct ieee80211_he_6ghz_oper_info { u8 min_rate; } STRUCT_PACKED; +/* IEEE Std 802.11ax-2021, Figure 9-788l - Control field format */ #define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1)) #define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2) +#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_MASK (BIT(3) | BIT(4) | BIT(5)) +#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT 3 -/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */ +/* IEEE Std 802.11ax-2021, 9.4.2.263 HE 6 GHz Band Capabilities element */ struct ieee80211_he_6ghz_band_cap { /* Minimum MPDU Start Spacing B0..B2 * Maximum A-MPDU Length Exponent B3..B5 - * Maximum MPDU Length B6..B7 */ - le16 capab; + * Maximum MPDU Length B6..B7 + * SM Power Save B9..B10 + * RD Responder B11 + * Rx Antenna Pattern Consistency B12 + * Tx Antenna Consistency B13 */ + le16 capab; /* Capabilities Information field */ } STRUCT_PACKED; #define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2)) @@ -2252,7 +2286,7 @@ struct ieee80211_he_6ghz_band_cap { #define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13) /* - * IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element + * IEEE Std 802.11ax-2021, 9.4.2.252 Spatial Reuse Parameter Set element */ struct ieee80211_spatial_reuse { u8 sr_ctrl; /* SR Control */ @@ -2323,6 +2357,7 @@ struct ieee80211_6ghz_operation_info { #define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30)) #define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31)) #define HE_OPERATION_BSS_COLOR_OFFSET 24 +#define HE_OPERATION_BSS_COLOR_MAX 64 /* HE operation fields length*/ #define HE_OPERATION_IE_MIN_LEN 6 @@ -2330,6 +2365,17 @@ struct ieee80211_6ghz_operation_info { #define HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN 1 #define HE_OPERATION_6GHZ_OPER_INFO_LEN 5 +/** + * enum he_6ghz_ap_type - Allowed Access Point types for 6 GHz Band + * + * IEEE Std 802.11ax-2021, Table E-12 (Regulatory Info subfield encoding in the + * United States) + */ +enum he_6ghz_ap_type { + HE_6GHZ_INDOOR_AP = 0, + HE_6GHZ_STANDARD_POWER_AP = 1, +}; + /* Spatial Reuse defines */ #define SPATIAL_REUSE_SRP_DISALLOWED BIT(0) #define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1) @@ -2394,6 +2440,105 @@ struct ieee80211_he_mu_edca_parameter_set { #define RNR_BSS_PARAM_CO_LOCATED BIT(6) #define RNR_20_MHZ_PSD_MAX_TXPOWER 255 /* dBm */ +/* IEEE P802.11be/D1.5, 9.4.2.311 - EHT Operation element */ + +/* Figure 9-1002b: EHT Operation Parameters field subfields */ +#define EHT_OPER_INFO_PRESENT BIT(0) +#define EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1) + +/* Control subfield: Channel Width subfield; see Table 9-401b */ +#define EHT_OPER_CHANNEL_WIDTH_20MHZ 0 +#define EHT_OPER_CHANNEL_WIDTH_40MHZ 1 +#define EHT_OPER_CHANNEL_WIDTH_80MHZ 2 +#define EHT_OPER_CHANNEL_WIDTH_160MHZ 3 +#define EHT_OPER_CHANNEL_WIDTH_320MHZ 4 + +/* Figure 9-1002c: EHT Operation Information field format */ +struct ieee80211_eht_oper_info { + u8 control; /* B0..B2: Channel Width */ + u8 ccfs0; + u8 ccfs1; + le16 disabled_chan_bitmap; /* 0 or 2 octets */ +} STRUCT_PACKED; + +/* Figure 9-1002a: EHT Operation element format */ +struct ieee80211_eht_operation { + u8 oper_params; /* EHT Operation Parameters: EHT_OPER_* bits */ + struct ieee80211_eht_oper_info oper_info; /* 0 or 3 or 5 octets */ +} STRUCT_PACKED; + +/* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */ + +/* Figure 9-1002af: EHT MAC Capabilities Information field */ +#define EHT_MACCAP_EPCS_PRIO BIT(0) +#define EHT_MACCAP_OM_CONTROL BIT(1) +#define EHT_MACCAP_TRIGGERED_TXOP_MODE1 BIT(2) +#define EHT_MACCAP_TRIGGERED_TXOP_MODE2 BIT(3) +#define EHT_MACCAP_RESTRICTED_TWT BIT(4) +#define EHT_MACCAP_SCS_TRAFFIC_DESC BIT(5) +#define EHT_MACCAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7)) +#define EHT_MACCAP_MAX_MPDU_LEN_3895 0 +#define EHT_MACCAP_MAX_MPDU_LEN_7991 BIT(6) +#define EHT_MACCAP_MAX_MPDU_LEN_11454 BIT(7) +#define EHT_MACCAP_MAX_AMPDU_LEN_EXP_EXT BIT(8) + +/* Figure 9-1002ag: EHT PHY Capabilities Information field format + * _IDX indicates the octet index within the field */ +#define EHT_PHY_CAPAB_LEN 9 + +#define EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX 0 +#define EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK ((u8) BIT(1)) + +#define EHT_PHYCAP_SU_BEAMFORMER_IDX 0 +#define EHT_PHYCAP_SU_BEAMFORMER ((u8) BIT(5)) +#define EHT_PHYCAP_SU_BEAMFORMEE_IDX 0 +#define EHT_PHYCAP_SU_BEAMFORMEE ((u8) BIT(6)) + +#define EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 5 +#define EHT_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(3)) + +#define EHT_PHYCAP_MU_BEAMFORMER_IDX 7 +#define EHT_PHYCAP_MU_BEAMFORMER_80MHZ ((u8) BIT(4)) +#define EHT_PHYCAP_MU_BEAMFORMER_160MHZ ((u8) BIT(5)) +#define EHT_PHYCAP_MU_BEAMFORMER_320MHZ ((u8) BIT(6)) +#define EHT_PHYCAP_MU_BEAMFORMER_MASK (EHT_PHYCAP_MU_BEAMFORMER_80MHZ | \ + EHT_PHYCAP_MU_BEAMFORMER_160MHZ | \ + EHT_PHYCAP_MU_BEAMFORMER_320MHZ) + +/* Figure 9-1002ah: Supported EHT-MCS and NSS Set field format */ +#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY 4 +#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS 3 + +#define EHT_MCS_NSS_CAPAB_LEN 9 +/* + * Figure 9-1002ak: EHT PPE Thresholds field format + * Maximum PPE threshold length: 62 octets + * NSS: 4 bits (maximum NSS: 16), RU index: 5 bits, each pair: 6 bits + * 4 + 5 + 5 * 16 * 6 = 489 bits, Padding: 7 bits + */ +#define EHT_PPE_THRESH_CAPAB_LEN 62 + +/* 9.4.2.313.5: EHT PPE Thresholds field */ +#define EHT_PPE_THRES_NSS_SHIFT 0 +#define EHT_PPE_THRES_NSS_MASK ((u8) (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3))) +#define EHT_PPE_THRES_RU_INDEX_SHIFT 4 +#define EHT_PPE_THRES_RU_INDEX_MASK ((u16) (BIT(4) | BIT(5) | \ + BIT(6) | BIT(7) | \ + BIT(8))) + +#define EHT_NSS_MAX_STREAMS 8 + +/* Figure 9-1002ae: EHT Capabilities element format */ +struct ieee80211_eht_capabilities { + /* EHT MAC Capabilities Information */ + le16 mac_cap; + /* EHT PHY Capabilities Information */ + u8 phy_cap[EHT_PHY_CAPAB_LEN]; + /* Supported EHT-MCS And NSS Set and EHT PPE thresholds (Optional) */ + u8 optional[EHT_MCS_NSS_CAPAB_LEN + EHT_PPE_THRESH_CAPAB_LEN]; +} STRUCT_PACKED; + /* 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 @@ -2494,10 +2639,16 @@ enum mscs_description_subelem { #define FD_CAP_PHY_INDEX_SHIFT 10 /* - * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning + * IEEE Std 802.11ax-2021, 26.17.2.3.2, AP behavior for fast passive scanning */ #define FD_MAX_INTERVAL_6GHZ 20 /* TUs */ +/* IEEE Std 802.11ax-2021, 26.17.3.5.1: AP needs to wait and see the collision + * persists for at least the minimum default timeout + * dot11BSSColorCollisionAPPeriod (50 seconds) + */ +#define DOT11BSS_COLOR_COLLISION_AP_PERIOD 50 + /* Protected Vendor-specific QoS Management Action frame identifiers - WFA */ #define QM_ACTION_VENDOR_TYPE 0x506f9a1a #define QM_ACTION_OUI_TYPE 0x1a diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index 0f7d3af3..d04c8d18 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -1599,6 +1599,18 @@ enum qca_wlan_vendor_acs_hw_mode { * synchronous (in vendor command reply) to the request. Each TWT * operation is specifically mentioned (against its respective * documentation) to support either of these or both modes. + * @QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI: Flag indicates + * that the driver requires add/del virtual interface path using the + * generic nl80211 commands for NDP interface create/delete and to + * register/unregister the netdev instead of creating/deleting the NDP + * interface using the vendor commands + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE and + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE. With the latest kernel + * (5.12 version onward), interface creation/deletion is not allowed using + * vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK + * during the register/unregister of netdev. Create and delete NDP + * interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE + * commands respectively if the driver advertises this capability set. * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits */ enum qca_wlan_vendor_features { @@ -1617,6 +1629,7 @@ enum qca_wlan_vendor_features { QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R = 12, QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13, QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14, + QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI = 15, NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */ }; @@ -2390,7 +2403,10 @@ enum qca_wlan_vendor_attr_config { QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58, /* 8-bit unsigned value for ELNA bypass. - * 1-Enable, 0-Disable + * 0 - Disable eLNA bypass. + * 1 - Enable eLNA bypass. + * 2 - Reset eLNA bypass configuration, the driver should + * revert to the default configuration of eLNA bypass. */ QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59, @@ -5627,6 +5643,8 @@ enum qca_wlan_vendor_acs_select_reason { * current channel. */ QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE, + /* Represents the reason that ACS triggered by AFC */ + QCA_WLAN_VENDOR_ACS_SELECT_REASON_AFC_TRIGGER, }; /** @@ -5834,12 +5852,77 @@ enum qca_wlan_vendor_external_acs_event_chan_info_attr { */ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13, + /* + * 16-bit attribute of bits indicating the AP power modes supported by + * the channel (u16). + * Note: Currently, only 3 bits are used in the attribute and each bit + * corresponds to the power mode mentioned in enum + * qca_wlan_vendor_external_acs_chan_power_mode and a given bit is + * set if the associated mode is supported. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_SUPP_POWER_MODES + = 14, + /* Array of nested attributes for each power mode. It takes attr as + * defined in enum + * qca_wlan_vendor_external_acs_event_chan_power_info_attr. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR = 15, /* keep last */ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX = QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST - 1, }; +/** + * qca_wlan_vendor_external_acs_chan_power_mode - Specifies the valid + * values that the vendor external ACS channel power attribute + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE can + * take. + * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER: Low power/Indoor mode + * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER: Standard power mode + * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER: Very low power mode + */ +enum qca_wlan_vendor_external_acs_chan_power_level { + QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER = 0, + QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER = 1, + QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER = 2, +}; + +/** + * qca_wlan_vendor_external_acs_event_chan_power_info_attr: Represents nested + * attributes for power mode type and power values corresponding to that. + * These attributes are sent as part of + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR. + */ +enum qca_wlan_vendor_external_acs_event_chan_power_info_attr { + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_INVALID = 0, + /* + * Power mode (u8) takes the values defined in enum + * qca_wlan_vendor_external_acs_chan_power_mode + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE + = 1, + /* + * Indicates if power value is a PSD/EIRP value (flag). If flag is + * present, it indicates a PSD value. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG = 2, + /* + * Power value (u32) PSD/EIRP as indicated by + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG, + * for power mode corresponding to the + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE. + * Units for PSD - dBm/MHz + * Units for EIRP - dBm + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_VALUE + = 3, + /* keep last */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST, + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_MAX = + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST - 1, +}; + /** * qca_wlan_vendor_attr_pcl: Represents attributes for * preferred channel list (PCL). These attributes are sent as part of @@ -5864,6 +5947,10 @@ enum qca_wlan_vendor_attr_pcl { * bit 3 set: channel should be excluded in GO negotiation */ QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_PCL_LAST, + QCA_WLAN_VENDOR_ATTR_PCL_MAX = QCA_WLAN_VENDOR_ATTR_PCL_LAST - 1 }; /** @@ -5926,6 +6013,10 @@ enum qca_wlan_vendor_attr_external_acs_event { * qca_wlan_vendor_attr_rropavail_info. */ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14, + /* Flag attribute to indicate if driver supports 6 GHz AFC trigger + * for External ACS + */ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AFC_CAPABILITY = 15, /* keep last */ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST, @@ -6529,6 +6620,12 @@ enum qca_wlan_vendor_attr_spectral_scan { * for the current operating bandwidth. */ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH = 30, + /* Spectral FFT recapture flag attribute, to enable FFT recapture. + * Recapture can only be enabled for scan period greater than 52 us. + * If this attribute is enabled, re-triggers will be enabled when AGC + * gain changes. + */ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_RECAPTURE = 31, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX = @@ -7032,7 +7129,7 @@ enum qca_wlan_vendor_attr_rtplinst { * Use XR level to benefit XR (extended reality) application to achieve * latency and power by via constraint scan/roaming/adaptive PS. * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW: - * Use low latency level to benifit application like concurrent + * Use low latency level to benefit application like concurrent * downloading or video streaming via constraint scan/adaptive PS. * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW: * Use ultra low latency level to benefit for gaming/voice @@ -7356,6 +7453,14 @@ enum qca_wlan_vendor_attr_ndp_params { * 1:support 0:not support */ QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30, + /* As per Wi-Fi Aware Specification v3.2 Service Id is the first + * 48 bits of the SHA-256 hash of the Service Name. + * A lower-case representation of the Service Name shall be used to + * calculate the Service ID. + * Array of u8: length is 6 bytes + * This attribute is used and optional for ndp indication. + */ + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID = 31, /* keep last */ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST, @@ -7365,9 +7470,24 @@ enum qca_wlan_vendor_attr_ndp_params { enum qca_wlan_ndp_sub_cmd { QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0, - /* Command to create a NAN data path interface */ + /* Command to create a NAN data path interface. + * This command was initially designed to both create and start a NAN + * data path interface. However, changes to Linux 5.12 no longer allow + * interface creation via vendor commands. When the driver advertises + * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI + * userspace must explicitly first create the interface using + * NL80211_CMD_NEW_INTERFACE before subsequently invoking this command + * to start the interface. + */ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1, - /* Command to delete a NAN data path interface */ + /* Command to delete a NAN data path interface. + * This command was initially designed to both stop and delete a NAN + * data path interface. However, changes to Linux 5.12 no longer allow + * interface deletion via vendor commands. When the driver advertises + * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI + * userspace must explicitly delete the interface using + * NL80211_CMD_DEL_INTERFACE after calling this command. + */ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2, /* Command to initiate a NAN data path session */ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3, @@ -8515,6 +8635,18 @@ enum qca_wlan_vendor_attr_wifi_test_config { */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT = 57, + /* 8-bit unsigned value to configure the driver/firmware to allow eMLSR + * mode for IEEE 802.11be MLO capable devices. If the attribute is set + * to 1, and if the firmware supports this capability too, the STA + * advertises this capability to the AP over Association Request frame. + * This attribute will not have any effect on legacy devices with no + * IEEE 802.11be support. + * 0 - Default behavior + * 1 - Enable eMLSR (Enhanced Multi-link Single-Radio) mode + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE = 58, + /* keep last */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX = @@ -8585,12 +8717,17 @@ enum qca_wlan_vendor_attr_wifi_test_config { * peer. Refers the enum qca_wlan_vendor_attr_twt_capability. It's a synchronous * operation. * - * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmare is + * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmware is * ready for a new TWT session setup after it issued a TWT teardown. * * @QCA_WLAN_TWT_SET_PARAM: Configure TWT related parameters. Required * parameters are obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refer * the enum qca_wlan_vendor_attr_twt_set_param. + * + * @QCA_WLAN_TWT_NOTIFY: Used to notify userspace about changes in TWT + * related information for example TWT required bit in AP capabilities etc. + * The reason for the notification is sent using + * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS. */ enum qca_wlan_twt_operation { QCA_WLAN_TWT_SET = 0, @@ -8604,6 +8741,7 @@ enum qca_wlan_twt_operation { QCA_WLAN_TWT_GET_CAPABILITIES = 8, QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9, QCA_WLAN_TWT_SET_PARAM = 10, + QCA_WLAN_TWT_NOTIFY = 11, }; /** @@ -8620,11 +8758,17 @@ enum qca_wlan_twt_operation { * enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume, * enum qca_wlan_vendor_attr_twt_set_param, or * enum qca_wlan_vendor_attr_twt_stats based on the operation. + * + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS: Size is u8, mandatory when + * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION is set to QCA_WLAN_TWT_NOTIFY. + * The values used by this attribute are defined in + * enum qca_wlan_vendor_twt_status. */ enum qca_wlan_vendor_attr_config_twt { QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION = 1, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS = 2, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS = 3, /* keep last */ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST, @@ -9100,6 +9244,10 @@ enum qca_wlan_vendor_attr_twt_setup { * QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE: The driver requested to * terminate an existing TWT session on power save exit request from userspace. * Used on the TWT_TERMINATE notification from the driver/firmware. + * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED: The peer has set the TWT + * required bit in its capabilities. + * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED: The peer has cleared + * the TWT required bit(1->0) in its capabilities. */ enum qca_wlan_vendor_twt_status { QCA_WLAN_VENDOR_TWT_STATUS_OK = 0, @@ -9125,6 +9273,8 @@ enum qca_wlan_vendor_twt_status { QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20, QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS = 21, QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE = 22, + QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED = 23, + QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED = 24, }; /** diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index b78db05a..27336c92 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1599,6 +1599,13 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, "%s: invalid group cipher 0x%x (%08x)", __func__, data->group_cipher, WPA_GET_BE32(pos)); +#ifdef CONFIG_NO_TKIP + if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) { + wpa_printf(MSG_DEBUG, + "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build", + __func__); + } +#endif /* CONFIG_NO_TKIP */ return -1; } pos += RSN_SELECTOR_LEN; diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index c1ce68c1..779b2cf8 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -487,7 +487,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; - struct os_reltime started_at; + struct os_reltime started_at, ending_at; int res; fd_set rfds; const char *_cmd; @@ -543,9 +543,19 @@ retry_send: } os_free(cmd_buf); + os_get_reltime(&ending_at); + ending_at.sec += 10; + for (;;) { - tv.tv_sec = 10; - tv.tv_usec = 0; + struct os_reltime diff; + + os_get_reltime(&started_at); + if (os_reltime_before(&ending_at, &started_at)) + return -2; + os_reltime_sub(&ending_at, &started_at, &diff); + tv.tv_sec = diff.sec; + tv.tv_usec = diff.usec; + FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 3d3a62a1..055bf730 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -363,6 +363,9 @@ extern "C" { #define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED " #define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON " +/* BSS Transition Management Query frame received */ +#define BSS_TM_QUERY "BSS-TM-QUERY " + /* BSS Transition Management Response frame received */ #define BSS_TM_RESP "BSS-TM-RESP " diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index e6150b0c..e4f3eb3e 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -1275,4 +1275,46 @@ struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, struct crypto_ec_key *key, enum crypto_hash_alg algo); +struct crypto_rsa_key; + +/** + * crypto_rsa_key_read - Read an RSA key + * @file: File from which to read (PEM encoded, can be X.509v3 certificate) + * @private_key: Whether to read the private key instead of public key + * Returns: RSA key or %NULL on failure + */ +struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key); + +/** + * crypto_rsa_oaep_sha256_encrypt - RSA-OAEP-SHA-256 encryption + * @key: RSA key from crypto_rsa_key_read() + * @in: Plaintext input data + * Returns: Encrypted output data or %NULL on failure + */ +struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key, + const struct wpabuf *in); + +/** + * crypto_rsa_oaep_sha256_decrypt - RSA-OAEP-SHA-256 decryption + * @key: RSA key from crypto_rsa_key_read() + * @in: Encrypted input data + * Returns: Decrypted output data or %NULL on failure + */ +struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key, + const struct wpabuf *in); + +/** + * crypto_rsa_key_free - Free an RSA key + * @key: RSA key from crypto_rsa_key_read() + */ +void crypto_rsa_key_free(struct crypto_rsa_key *key); + +/** + * crypto_unload - Unload crypto resources + * + * This function is called just before the process exits to allow dynamic + * resource allocations to be freed. + */ +void crypto_unload(void); + #endif /* CRYPTO_H */ diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c index 4ef11462..a7a163f5 100644 --- a/src/crypto/crypto_gnutls.c +++ b/src/crypto/crypto_gnutls.c @@ -504,3 +504,8 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) gcry_cipher_close(ctx->dec); os_free(ctx); } + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c index aad40af1..d15c363c 100644 --- a/src/crypto/crypto_internal.c +++ b/src/crypto/crypto_internal.c @@ -326,3 +326,8 @@ int crypto_global_init(void) void crypto_global_deinit(void) { } + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c index ed30efa0..fd79c1a4 100644 --- a/src/crypto/crypto_libtomcrypt.c +++ b/src/crypto/crypto_libtomcrypt.c @@ -766,3 +766,8 @@ fail: } #endif /* CONFIG_MODEXP */ + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/crypto_linux.c b/src/crypto/crypto_linux.c index 17244561..9278e279 100644 --- a/src/crypto/crypto_linux.c +++ b/src/crypto/crypto_linux.c @@ -1007,3 +1007,8 @@ int crypto_global_init(void) void crypto_global_deinit(void) { } + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c index f85d3653..d7450277 100644 --- a/src/crypto/crypto_nettle.c +++ b/src/crypto/crypto_nettle.c @@ -467,3 +467,8 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) { bin_clear_free(ctx, sizeof(*ctx)); } + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/crypto_none.c b/src/crypto/crypto_none.c index 54791941..a0dc0f52 100644 --- a/src/crypto/crypto_none.c +++ b/src/crypto/crypto_none.c @@ -22,3 +22,8 @@ int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { return 0; } + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 82c85762..c6e065f8 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -1,6 +1,6 @@ /* * Wrapper functions for OpenSSL libcrypto - * Copyright (c) 2004-2017, Jouni Malinen + * Copyright (c) 2004-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -16,16 +16,17 @@ #include #include #include -#ifdef CONFIG_OPENSSL_CMAC -#include -#endif /* CONFIG_OPENSSL_CMAC */ +#include #ifdef CONFIG_ECC #include #include -#include #endif /* CONFIG_ECC */ #if OPENSSL_VERSION_NUMBER >= 0x30000000L #include +#include +#include +#else /* OpenSSL version >= 3.0 */ +#include #endif /* OpenSSL version >= 3.0 */ #include "common.h" @@ -40,9 +41,7 @@ #include "aes_wrap.h" #include "crypto.h" -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L /* Compatibility wrappers for older versions. */ static HMAC_CTX * HMAC_CTX_new(void) @@ -121,30 +120,89 @@ static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) #endif /* OpenSSL version < 1.1.0 */ +#if OPENSSL_VERSION_NUMBER < 0x10101000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x30400000L) + +static int EC_POINT_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) +{ + return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx); +} + + +static int EC_POINT_set_affine_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, BN_CTX *ctx) +{ + return EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx); +} + +#endif /* OpenSSL version < 1.1.1 */ + + +#if OPENSSL_VERSION_NUMBER < 0x10101000L || \ + defined(OPENSSL_IS_BORINGSSL) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x30400000L) + +static int EC_POINT_set_compressed_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + int y_bit, BN_CTX *ctx) +{ + return EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, + ctx); +} + + +static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx) +{ + return EC_GROUP_get_curve_GFp(group, p, a, b, ctx); +} + +#endif /* OpenSSL version < 1.1.1 */ + + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static OSSL_PROVIDER *openssl_default_provider = NULL; +static OSSL_PROVIDER *openssl_legacy_provider = NULL; +#endif /* OpenSSL version >= 3.0 */ + void openssl_load_legacy_provider(void) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L - static bool loaded = false; - OSSL_PROVIDER *legacy; - - if (loaded) + if (openssl_legacy_provider) return; - legacy = OSSL_PROVIDER_load(NULL, "legacy"); + openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy"); + if (openssl_legacy_provider && !openssl_default_provider) + openssl_default_provider = OSSL_PROVIDER_load(NULL, "default"); +#endif /* OpenSSL version >= 3.0 */ +} - if (legacy) { - OSSL_PROVIDER_load(NULL, "default"); - loaded = true; + +static void openssl_unload_legacy_provider(void) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (openssl_legacy_provider) { + OSSL_PROVIDER_unload(openssl_legacy_provider); + openssl_legacy_provider = NULL; + } + if (openssl_default_provider) { + OSSL_PROVIDER_unload(openssl_default_provider); + openssl_default_provider = NULL; } #endif /* OpenSSL version >= 3.0 */ } +#if OPENSSL_VERSION_NUMBER < 0x30000000L + static BIGNUM * get_group5_prime(void) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !(defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L return BN_get_rfc3526_prime_1536(NULL); #elif !defined(OPENSSL_IS_BORINGSSL) return get_rfc3526_prime_1536(NULL); @@ -195,6 +253,8 @@ static BIGNUM * get_group5_order(void) return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL); } +#endif /* OpenSSL version < 3.0 */ + #ifdef OPENSSL_NO_SHA256 #define NO_SHA256_WRAPPER @@ -403,7 +463,7 @@ void * aes_encrypt_init(const u8 *key, size_t len) if (ctx == NULL) return NULL; if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) { - os_free(ctx); + EVP_CIPHER_CTX_free(ctx); return NULL; } EVP_CIPHER_CTX_set_padding(ctx, 0); @@ -501,8 +561,52 @@ void aes_decrypt_deinit(void *ctx) #ifndef CONFIG_FIPS #ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static const EVP_CIPHER * aes_get_evp_wrap_cipher(size_t keylen) +{ + switch (keylen) { + case 16: + return EVP_aes_128_wrap(); + case 24: + return EVP_aes_192_wrap(); + case 32: + return EVP_aes_256_wrap(); + default: + return NULL; + } +} +#endif /* OpenSSL version >= 3.0 */ + + int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *type; + int ret = -1, len; + u8 buf[16]; + + if (TEST_FAIL()) + return -1; + + type = aes_get_evp_wrap_cipher(kek_len); + if (!type) + return -1; + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + return -1; + + if (EVP_EncryptInit_ex(ctx, type, NULL, kek, NULL) == 1 && + EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 && + EVP_EncryptUpdate(ctx, cipher, &len, plain, n * 8) == 1 && + len == (n + 1) * 8 && + EVP_EncryptFinal_ex(ctx, buf, &len) == 1) + ret = 0; + + EVP_CIPHER_CTX_free(ctx); + return ret; +#else /* OpenSSL version >= 3.0 */ AES_KEY actx; int res; @@ -513,12 +617,40 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8); OPENSSL_cleanse(&actx, sizeof(actx)); return res <= 0 ? -1 : 0; +#endif /* OpenSSL version >= 3.0 */ } int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *type; + int ret = -1, len; + u8 buf[16]; + + if (TEST_FAIL()) + return -1; + + type = aes_get_evp_wrap_cipher(kek_len); + if (!type) + return -1; + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + return -1; + + if (EVP_DecryptInit_ex(ctx, type, NULL, kek, NULL) == 1 && + EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 && + EVP_DecryptUpdate(ctx, plain, &len, cipher, (n + 1) * 8) == 1 && + len == n * 8 && + EVP_DecryptFinal_ex(ctx, buf, &len) == 1) + ret = 0; + + EVP_CIPHER_CTX_free(ctx); + return ret; +#else /* OpenSSL version >= 3.0 */ AES_KEY actx; int res; @@ -529,6 +661,7 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8); OPENSSL_cleanse(&actx, sizeof(actx)); return res <= 0 ? -1 : 0; +#endif /* OpenSSL version >= 3.0 */ } #endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */ @@ -819,9 +952,7 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L DH *dh; struct wpabuf *pubkey = NULL, *privkey = NULL; size_t publen, privlen; @@ -870,6 +1001,57 @@ err: wpabuf_clear_free(privkey); DH_free(dh); return NULL; +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = NULL; + OSSL_PARAM params[2]; + size_t pub_len = OSSL_PARAM_UNMODIFIED; + size_t priv_len; + struct wpabuf *pubkey = NULL, *privkey = NULL; + BIGNUM *priv_bn = NULL; + EVP_PKEY_CTX *gctx; + + *priv = NULL; + wpabuf_free(*publ); + *publ = NULL; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + "modp_1536", 0); + params[1] = OSSL_PARAM_construct_end(); + + gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (!gctx || + EVP_PKEY_keygen_init(gctx) != 1 || + EVP_PKEY_CTX_set_params(gctx, params) != 1 || + EVP_PKEY_generate(gctx, &pkey) != 1 || + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, + &priv_bn) != 1 || + EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, + NULL, 0, &pub_len) < 0 || + pub_len == OSSL_PARAM_UNMODIFIED || + (priv_len = BN_num_bytes(priv_bn)) == 0 || + !(pubkey = wpabuf_alloc(pub_len)) || + !(privkey = wpabuf_alloc(priv_len)) || + EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, + wpabuf_put(pubkey, pub_len), + pub_len, NULL) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(pubkey); + wpabuf_clear_free(privkey); + EVP_PKEY_free(pkey); + pkey = NULL; + } else { + BN_bn2bin(priv_bn, wpabuf_put(privkey, priv_len)); + + *priv = privkey; + *publ = pubkey; + } + + BN_clear_free(priv_bn); + EVP_PKEY_CTX_free(gctx); + return pkey; #else DH *dh; struct wpabuf *pubkey = NULL, *privkey = NULL; @@ -929,9 +1111,7 @@ err: void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L DH *dh; dh = DH_new(); @@ -962,6 +1142,39 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) err: DH_free(dh); return NULL; +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = NULL; + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + BIGNUM *priv_key, *pub_key; + EVP_PKEY_CTX *fctx; + + fctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL); + pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL); + bld = OSSL_PARAM_BLD_new(); + if (!fctx || !priv_key || !pub_key || !bld || + OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + "modp_1536", 0) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, + priv_key) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, + pub_key) != 1 || + !(params = OSSL_PARAM_BLD_to_param(bld)) || + EVP_PKEY_fromdata_init(fctx) != 1 || + EVP_PKEY_fromdata(fctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_fromdata failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(pkey); + pkey = NULL; + } + + BN_clear_free(priv_key); + BN_free(pub_key); + EVP_PKEY_CTX_free(fctx); + OSSL_PARAM_BLD_free(bld); + OSSL_PARAM_free(params); + return pkey; #else DH *dh; BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL; @@ -1004,6 +1217,36 @@ err: struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, const struct wpabuf *own_private) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = ctx; + EVP_PKEY *peer_pub; + size_t len; + struct wpabuf *res = NULL; + EVP_PKEY_CTX *dctx = NULL; + + peer_pub = EVP_PKEY_new(); + if (!pkey || !peer_pub || + EVP_PKEY_copy_parameters(peer_pub, pkey) != 1 || + EVP_PKEY_set1_encoded_public_key(peer_pub, wpabuf_head(peer_public), + wpabuf_len(peer_public)) != 1 || + !(dctx = EVP_PKEY_CTX_new(pkey, NULL)) || + EVP_PKEY_derive_init(dctx) != 1 || + EVP_PKEY_derive_set_peer(dctx, peer_pub) != 1 || + EVP_PKEY_derive(dctx, NULL, &len) != 1 || + !(res = wpabuf_alloc(len)) || + EVP_PKEY_derive(dctx, wpabuf_mhead(res), &len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(res); + res = NULL; + } else { + wpabuf_put(res, len); + } + + EVP_PKEY_free(peer_pub); + EVP_PKEY_CTX_free(dctx); + return res; +#else /* OpenSSL version >= 3.0 */ BIGNUM *pub_key; struct wpabuf *res = NULL; size_t rlen; @@ -1035,27 +1278,93 @@ err: BN_clear_free(pub_key); wpabuf_clear_free(res); return NULL; +#endif /* OpenSSL version >= 3.0 */ } void dh5_free(void *ctx) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = ctx; + + EVP_PKEY_free(pkey); +#else /* OpenSSL version >= 3.0 */ DH *dh; if (ctx == NULL) return; dh = ctx; DH_free(dh); +#endif /* OpenSSL version >= 3.0 */ } struct crypto_hash { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_CTX *ctx; +#else /* OpenSSL version >= 3.0 */ HMAC_CTX *ctx; +#endif /* OpenSSL version >= 3.0 */ }; struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct crypto_hash *ctx; + EVP_MAC *mac; + OSSL_PARAM params[2]; + char *a = NULL; + + switch (alg) { +#ifndef OPENSSL_NO_MD5 + case CRYPTO_HASH_ALG_HMAC_MD5: + a = "MD5"; + break; +#endif /* OPENSSL_NO_MD5 */ +#ifndef OPENSSL_NO_SHA + case CRYPTO_HASH_ALG_HMAC_SHA1: + a = "SHA1"; + break; +#endif /* OPENSSL_NO_SHA */ +#ifndef OPENSSL_NO_SHA256 +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + a = "SHA256"; + break; +#endif /* CONFIG_SHA256 */ +#endif /* OPENSSL_NO_SHA256 */ + default: + return NULL; + } + + mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!mac) + return NULL; + + params[0] = OSSL_PARAM_construct_utf8_string("digest", a, 0); + params[1] = OSSL_PARAM_construct_end(); + + ctx = os_zalloc(sizeof(*ctx)); + if (!ctx) + return NULL; + ctx->ctx = EVP_MAC_CTX_new(mac); + if (!ctx->ctx) { + EVP_MAC_free(mac); + os_free(ctx); + return NULL; + } + + if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) { + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + EVP_MAC_free(mac); + return NULL; + } + + EVP_MAC_free(mac); + return ctx; +#else /* OpenSSL version >= 3.0 */ struct crypto_hash *ctx; const EVP_MD *md; @@ -1097,6 +1406,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, } return ctx; +#endif /* OpenSSL version >= 3.0 */ } @@ -1104,12 +1414,49 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) { if (ctx == NULL) return; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_update(ctx->ctx, data, len); +#else /* OpenSSL version >= 3.0 */ HMAC_Update(ctx->ctx, data, len); +#endif /* OpenSSL version >= 3.0 */ } int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + size_t mdlen; + int res; + + if (!ctx) + return -2; + + if (!mac || !len) { + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + return 0; + } + + res = EVP_MAC_final(ctx->ctx, NULL, &mdlen, 0); + if (res != 1) { + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + return -1; + } + res = EVP_MAC_final(ctx->ctx, mac, &mdlen, mdlen); + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + + if (TEST_FAIL()) + return -1; + + if (res == 1) { + *len = mdlen; + return 0; + } + + return -1; +#else /* OpenSSL version >= 3.0 */ unsigned int mdlen; int res; @@ -1136,9 +1483,148 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) } return -1; +#endif /* OpenSSL version >= 3.0 */ } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +static int openssl_hmac_vector(char *digest, const u8 *key, + size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac, + unsigned int mdlen) +{ + EVP_MAC *hmac; + OSSL_PARAM params[2]; + EVP_MAC_CTX *ctx; + size_t i, mlen; + int res; + + if (TEST_FAIL()) + return -1; + + hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!hmac) + return -1; + + params[0] = OSSL_PARAM_construct_utf8_string("digest", digest, 0); + params[1] = OSSL_PARAM_construct_end(); + + ctx = EVP_MAC_CTX_new(hmac); + EVP_MAC_free(hmac); + if (!ctx) + return -1; + + if (EVP_MAC_init(ctx, key, key_len, params) != 1) + goto fail; + + for (i = 0; i < num_elem; i++) { + if (EVP_MAC_update(ctx, addr[i], len[i]) != 1) + goto fail; + } + + res = EVP_MAC_final(ctx, mac, &mlen, mdlen); + EVP_MAC_CTX_free(ctx); + + return res == 1 ? 0 : -1; +fail: + EVP_MAC_CTX_free(ctx); + return -1; +} + + +#ifndef CONFIG_FIPS + +int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("MD5", key ,key_len, num_elem, addr, len, + mac, 16); +} + + +int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_FIPS */ + + +int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA1", key, key_len, num_elem, addr, + len, mac, 20); +} + + +int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + + +#ifdef CONFIG_SHA256 + +int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA256", key, key_len, num_elem, addr, + len, mac, 32); +} + + +int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA256 */ + + +#ifdef CONFIG_SHA384 + +int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA384", key, key_len, num_elem, addr, + len, mac, 48); +} + + +int hmac_sha384(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA384 */ + + +#ifdef CONFIG_SHA512 + +int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA512", key, key_len, num_elem, addr, + len, mac, 64); +} + + +int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA512 */ + +#else /* OpenSSL version >= 3.0 */ + static int openssl_hmac_vector(const EVP_MD *type, const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac, @@ -1188,16 +1674,6 @@ int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, #endif /* CONFIG_FIPS */ -int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen) -{ - if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid, - ssid_len, iterations, buflen, buf) != 1) - return -1; - return 0; -} - - int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { @@ -1269,6 +1745,18 @@ int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, #endif /* CONFIG_SHA512 */ +#endif /* OpenSSL version >= 3.0 */ + + +int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid, + ssid_len, iterations, buflen, buf) != 1) + return -1; + return 0; +} + int crypto_get_random(void *buf, size_t len) { @@ -1278,10 +1766,49 @@ int crypto_get_random(void *buf, size_t len) } -#ifdef CONFIG_OPENSSL_CMAC int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_CTX *ctx = NULL; + EVP_MAC *emac; + int ret = -1; + size_t outlen, i; + OSSL_PARAM params[2]; + char *cipher = NULL; + + if (TEST_FAIL()) + return -1; + + emac = EVP_MAC_fetch(NULL, "CMAC", NULL); + + if (key_len == 32) + cipher = "aes-256-cbc"; + else if (key_len == 24) + cipher = "aes-192-cbc"; + else if (key_len == 16) + cipher = "aes-128-cbc"; + + params[0] = OSSL_PARAM_construct_utf8_string("cipher", cipher, 0); + params[1] = OSSL_PARAM_construct_end(); + + if (!emac || !cipher || + !(ctx = EVP_MAC_CTX_new(emac)) || + EVP_MAC_init(ctx, key, key_len, params) != 1) + goto fail; + + for (i = 0; i < num_elem; i++) { + if (!EVP_MAC_update(ctx, addr[i], len[i])) + goto fail; + } + if (EVP_MAC_final(ctx, mac, &outlen, 16) != 1 || outlen != 16) + goto fail; + + ret = 0; +fail: + EVP_MAC_CTX_free(ctx); + return ret; +#else /* OpenSSL version >= 3.0 */ CMAC_CTX *ctx; int ret = -1; size_t outlen, i; @@ -1296,6 +1823,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, if (key_len == 32) { if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL)) goto fail; + } else if (key_len == 24) { + if (!CMAC_Init(ctx, key, 24, EVP_aes_192_cbc(), NULL)) + goto fail; } else if (key_len == 16) { if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL)) goto fail; @@ -1313,6 +1843,7 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, fail: CMAC_CTX_free(ctx); return ret; +#endif /* OpenSSL version >= 3.0 */ } @@ -1333,7 +1864,6 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) { return omac1_aes_vector(key, 32, 1, &data, &data_len, mac); } -#endif /* CONFIG_OPENSSL_CMAC */ struct crypto_bignum * crypto_bignum_init(void) @@ -1752,7 +2282,7 @@ struct crypto_ec * crypto_ec_init(int group) e->b = BN_new(); if (e->group == NULL || e->bnctx == NULL || e->prime == NULL || e->order == NULL || e->a == NULL || e->b == NULL || - !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) || + !EC_GROUP_get_curve(e->group, e->prime, e->a, e->b, e->bnctx) || !EC_GROUP_get_order(e->group, e->order, e->bnctx)) { crypto_ec_deinit(e); e = NULL; @@ -1847,10 +2377,10 @@ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p, struct crypto_bignum *x) { - return EC_POINT_get_affine_coordinates_GFp(e->group, - (const EC_POINT *) p, - (BIGNUM *) x, NULL, - e->bnctx) == 1 ? 0 : -1; + return EC_POINT_get_affine_coordinates(e->group, + (const EC_POINT *) p, + (BIGNUM *) x, NULL, + e->bnctx) == 1 ? 0 : -1; } @@ -1868,8 +2398,8 @@ int crypto_ec_point_to_bin(struct crypto_ec *e, y_bn = BN_new(); if (x_bn && y_bn && - EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point, - x_bn, y_bn, e->bnctx)) { + EC_POINT_get_affine_coordinates(e->group, (EC_POINT *) point, + x_bn, y_bn, e->bnctx)) { if (x) { crypto_bignum_to_bin((struct crypto_bignum *) x_bn, x, len, len); @@ -1907,8 +2437,7 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, return NULL; } - if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y, - e->bnctx)) { + if (!EC_POINT_set_affine_coordinates(e->group, elem, x, y, e->bnctx)) { EC_POINT_clear_free(elem); elem = NULL; } @@ -2009,8 +2538,8 @@ void crypto_ec_point_debug_print(const struct crypto_ec *e, x = BN_new(); y = BN_new(); if (!x || !y || - EC_POINT_get_affine_coordinates_GFp(e->group, (const EC_POINT *) p, - x, y, e->bnctx) != 1) + EC_POINT_get_affine_coordinates(e->group, (const EC_POINT *) p, + x, y, e->bnctx) != 1) goto fail; x_str = BN_bn2hex(x); @@ -2035,6 +2564,33 @@ struct crypto_ecdh { struct crypto_ecdh * crypto_ecdh_init(int group) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct crypto_ecdh *ecdh; + const char *name; + + ecdh = os_zalloc(sizeof(*ecdh)); + if (!ecdh) + goto fail; + + ecdh->ec = crypto_ec_init(group); + if (!ecdh->ec) + goto fail; + + name = OSSL_EC_curve_nid2name(ecdh->ec->nid); + if (!name) + goto fail; + + ecdh->pkey = EVP_EC_gen(name); + if (!ecdh->pkey) + goto fail; + +done: + return ecdh; +fail: + crypto_ecdh_deinit(ecdh); + ecdh = NULL; + goto done; +#else /* OpenSSL version >= 3.0 */ struct crypto_ecdh *ecdh; EVP_PKEY *params = NULL; EC_KEY *ec_params = NULL; @@ -2089,11 +2645,32 @@ fail: crypto_ecdh_deinit(ecdh); ecdh = NULL; goto done; +#endif /* OpenSSL version >= 3.0 */ } struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct crypto_ecdh *ecdh; + + ecdh = os_zalloc(sizeof(*ecdh)); + if (!ecdh) + goto fail; + + ecdh->ec = crypto_ec_init(group); + if (!ecdh->ec) + goto fail; + + ecdh->pkey = EVP_PKEY_dup((EVP_PKEY *) own_key); + if (!ecdh->pkey) + goto fail; + + return ecdh; +fail: + crypto_ecdh_deinit(ecdh); + return NULL; +#else /* OpenSSL version >= 3.0 */ struct crypto_ecdh *ecdh; ecdh = os_zalloc(sizeof(*ecdh)); @@ -2115,11 +2692,34 @@ struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key) fail: crypto_ecdh_deinit(ecdh); return NULL; +#endif /* OpenSSL version >= 3.0 */ } struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct wpabuf *buf = NULL; + unsigned char *pub; + size_t len, exp_len; + + len = EVP_PKEY_get1_encoded_public_key(ecdh->pkey, &pub); + if (len == 0) + return NULL; + + /* Encoded using SECG SEC 1, Sec. 2.3.4 format */ + exp_len = 1 + 2 * crypto_ec_prime_len(ecdh->ec); + if (len != exp_len) { + wpa_printf(MSG_ERROR, + "OpenSSL:%s: Unexpected encoded public key length %zu (expected %zu)", + __func__, len, exp_len); + goto fail; + } + buf = wpabuf_alloc_copy(pub + 1, inc_y ? len - 1 : len / 2); +fail: + OPENSSL_free(pub); + return buf; +#else /* OpenSSL version >= 3.0 */ struct wpabuf *buf = NULL; EC_KEY *eckey; const EC_POINT *pubkey; @@ -2145,10 +2745,10 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) if (!x || !buf) goto fail; - if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey, - x, y, ecdh->ec->bnctx) != 1) { + if (EC_POINT_get_affine_coordinates(ecdh->ec->group, pubkey, + x, y, ecdh->ec->bnctx) != 1) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_get_affine_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2175,12 +2775,57 @@ fail: wpabuf_free(buf); buf = NULL; goto done; +#endif /* OpenSSL version >= 3.0 */ } struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, const u8 *key, size_t len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *peerkey = EVP_PKEY_new(); + EVP_PKEY_CTX *ctx; + size_t res_len; + struct wpabuf *res = NULL; + u8 *peer; + + /* Encode using SECG SEC 1, Sec. 2.3.4 format */ + peer = os_malloc(1 + len); + if (!peer) + return NULL; + peer[0] = inc_y ? 0x04 : 0x02; + os_memcpy(peer + 1, key, len); + + if (!peerkey || + EVP_PKEY_copy_parameters(peerkey, ecdh->pkey) != 1 || + EVP_PKEY_set1_encoded_public_key(peerkey, peer, 1 + len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_set1_encoded_public_key failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(peerkey); + os_free(peer); + return NULL; + } + os_free(peer); + + ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL); + if (!ctx || + EVP_PKEY_derive_init(ctx) != 1 || + EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 || + EVP_PKEY_derive(ctx, NULL, &res_len) != 1 || + !(res = wpabuf_alloc(res_len)) || + EVP_PKEY_derive(ctx, wpabuf_mhead(res), &res_len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(res); + res = NULL; + } else { + wpabuf_put(res, res_len); + } + + EVP_PKEY_free(peerkey); + EVP_PKEY_CTX_free(ctx); + return res; +#else /* OpenSSL version >= 3.0 */ BIGNUM *x, *y = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *peerkey = NULL; @@ -2198,19 +2843,18 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, y = BN_bin2bn(key + len / 2, len / 2, NULL); if (!y) goto fail; - if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub, - x, y, - ecdh->ec->bnctx)) { + if (!EC_POINT_set_affine_coordinates(ecdh->ec->group, pub, + x, y, ecdh->ec->bnctx)) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_set_affine_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } - } else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group, - pub, x, 0, - ecdh->ec->bnctx)) { + } else if (!EC_POINT_set_compressed_coordinates(ecdh->ec->group, + pub, x, 0, + ecdh->ec->bnctx)) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_set_compressed_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2270,6 +2914,7 @@ fail: wpabuf_free(secret); secret = NULL; goto done; +#endif /* OpenSSL version >= 3.0 */ } @@ -2370,9 +3015,9 @@ struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x, if (!x || !y || !point) goto fail; - if (!EC_POINT_set_affine_coordinates_GFp(ec_group, point, x, y, ctx)) { + if (!EC_POINT_set_affine_coordinates(ec_group, point, x, y, ctx)) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_set_affine_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2777,12 +3422,53 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, } -struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, - const u8 *data, size_t len) +static int openssl_evp_pkey_ec_prime_len(struct crypto_ec_key *key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char gname[50]; + int nid; + EC_GROUP *group; + BIGNUM *prime = NULL; + int prime_len = -1; + + if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname), + NULL) != 1) + return -1; + nid = OBJ_txt2nid(gname); + group = EC_GROUP_new_by_curve_name(nid); + prime = BN_new(); + if (!group || !prime) + return -1; + if (EC_GROUP_get_curve(group, prime, NULL, NULL, NULL) == 1) + prime_len = BN_num_bytes(prime); + EC_GROUP_free(group); + BN_free(prime); + return prime_len; +#else const EC_GROUP *group; const EC_KEY *eckey; BIGNUM *prime = NULL; + int prime_len = -1; + + eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key); + if (!eckey) + goto fail; + group = EC_KEY_get0_group(eckey); + prime = BN_new(); + if (!prime || !group || + !EC_GROUP_get_curve(group, prime, NULL, NULL, NULL)) + goto fail; + prime_len = BN_num_bytes(prime); +fail: + BN_free(prime); + return prime_len; +#endif +} + + +struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, + const u8 *data, size_t len) +{ ECDSA_SIG *sig = NULL; const BIGNUM *r, *s; u8 *r_buf, *s_buf; @@ -2790,20 +3476,15 @@ struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, const unsigned char *p; int prime_len; + prime_len = openssl_evp_pkey_ec_prime_len(key); + if (prime_len < 0) + return NULL; + buf = crypto_ec_key_sign(key, data, len); if (!buf) return NULL; /* Extract (r,s) from Ecdsa-Sig-Value */ - eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key); - if (!eckey) - goto fail; - group = EC_KEY_get0_group(eckey); - prime = BN_new(); - if (!prime || !group || - !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL)) - goto fail; - prime_len = BN_num_bytes(prime); p = wpabuf_head(buf); sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf)); @@ -2822,7 +3503,6 @@ struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, goto fail; out: - BN_free(prime); ECDSA_SIG_free(sig); return buf; fail: @@ -2893,6 +3573,15 @@ fail: int crypto_ec_key_group(struct crypto_ec_key *key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char gname[50]; + int nid; + + if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname), + NULL) != 1) + return -1; + nid = OBJ_txt2nid(gname); +#else const EC_KEY *eckey; const EC_GROUP *group; int nid; @@ -2904,6 +3593,7 @@ int crypto_ec_key_group(struct crypto_ec_key *key) if (!group) return -1; nid = EC_GROUP_get_curve_name(group); +#endif switch (nid) { case NID_X9_62_prime256v1: return 19; @@ -2932,8 +3622,13 @@ int crypto_ec_key_group(struct crypto_ec_key *key) int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (EVP_PKEY_eq((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1) + return -1; +#else if (EVP_PKEY_cmp((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1) return -1; +#endif return 0; } @@ -3242,3 +3937,138 @@ struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, } #endif /* CONFIG_ECC */ + + +static EVP_PKEY * crypto_rsa_key_read_public(FILE *f) +{ + EVP_PKEY *pkey; + X509 *x509; + + pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (pkey) + return pkey; + + rewind(f); + x509 = PEM_read_X509(f, NULL, NULL, NULL); + if (!x509) + return NULL; + + pkey = X509_get_pubkey(x509); + X509_free(x509); + + if (!pkey) + return NULL; + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { + EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; +} + + +struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key) +{ + FILE *f; + EVP_PKEY *pkey; + + f = fopen(file, "r"); + if (!f) + return NULL; + if (private_key) + pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL); + else + pkey = crypto_rsa_key_read_public(f); + fclose(f); + return (struct crypto_rsa_key *) pkey; +} + + +#ifndef OPENSSL_NO_SHA256 + +struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key, + const struct wpabuf *in) +{ +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L + EVP_PKEY *pkey = (EVP_PKEY *) key; + EVP_PKEY_CTX *pkctx; + struct wpabuf *res = NULL; + size_t outlen; + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx) + goto fail; + + if (EVP_PKEY_encrypt_init(pkctx) != 1 || + EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 || + EVP_PKEY_encrypt(pkctx, NULL, &outlen, wpabuf_head(in), + wpabuf_len(in)) != 1 || + !(res = wpabuf_alloc(outlen)) || + EVP_PKEY_encrypt(pkctx, wpabuf_put(res, 0), &outlen, + wpabuf_head(in), wpabuf_len(in)) != 1) { + wpabuf_free(res); + res = NULL; + goto fail; + } + wpabuf_put(res, outlen); + +fail: + EVP_PKEY_CTX_free(pkctx); + return res; +#else + wpa_printf(MSG_ERROR, "%s() not supported", __func__); + return NULL; +#endif +} + + +struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key, + const struct wpabuf *in) +{ +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L + EVP_PKEY *pkey = (EVP_PKEY *) key; + EVP_PKEY_CTX *pkctx; + struct wpabuf *res = NULL; + size_t outlen; + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx) + goto fail; + + if (EVP_PKEY_decrypt_init(pkctx) != 1 || + EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 || + EVP_PKEY_decrypt(pkctx, NULL, &outlen, wpabuf_head(in), + wpabuf_len(in)) != 1 || + !(res = wpabuf_alloc(outlen)) || + EVP_PKEY_decrypt(pkctx, wpabuf_put(res, 0), &outlen, + wpabuf_head(in), wpabuf_len(in)) != 1) { + wpabuf_free(res); + res = NULL; + goto fail; + } + wpabuf_put(res, outlen); + +fail: + EVP_PKEY_CTX_free(pkctx); + return res; +#else + wpa_printf(MSG_ERROR, "%s() not supported", __func__); + return NULL; +#endif +} + +#endif /* OPENSSL_NO_SHA256 */ + + +void crypto_rsa_key_free(struct crypto_rsa_key *key) +{ + EVP_PKEY_free((EVP_PKEY *) key); +} + + +void crypto_unload(void) +{ + openssl_unload_legacy_provider(); +} diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c index 00ecf613..f47beebe 100644 --- a/src/crypto/crypto_wolfssl.c +++ b/src/crypto/crypto_wolfssl.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include @@ -85,6 +87,7 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) wc_ShaUpdate(&sha, addr[i], len[i]); wc_ShaFinal(&sha, mac); + wc_ShaFree(&sha); return 0; } @@ -106,6 +109,7 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, wc_Sha256Update(&sha256, addr[i], len[i]); wc_Sha256Final(&sha256, mac); + wc_Sha256Free(&sha256); return 0; } @@ -128,6 +132,7 @@ int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, wc_Sha384Update(&sha384, addr[i], len[i]); wc_Sha384Final(&sha384, mac); + wc_Sha384Free(&sha384); return 0; } @@ -150,6 +155,7 @@ int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, wc_Sha512Update(&sha512, addr[i], len[i]); wc_Sha512Final(&sha512, mac); + wc_Sha512Free(&sha512); return 0; } @@ -169,13 +175,16 @@ static int wolfssl_hmac_vector(int type, const u8 *key, if (TEST_FAIL()) return -1; - if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0) + if (wc_HmacInit(&hmac, NULL, INVALID_DEVID) != 0 || + wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0) return -1; for (i = 0; i < num_elem; i++) if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0) return -1; if (wc_HmacFinal(&hmac, mac) != 0) return -1; + wc_HmacFree(&hmac); + return 0; } @@ -274,9 +283,18 @@ int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen) { - if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid, - ssid_len, iterations, buflen, WC_SHA) != 0) + int ret; + + ret = wc_PBKDF2(buf, (const byte *) passphrase, os_strlen(passphrase), + ssid, ssid_len, iterations, buflen, WC_SHA); + if (ret != 0) { + if (ret == HMAC_MIN_KEYLEN_E) { + wpa_printf(MSG_ERROR, + "wolfSSL: Password is too short. Make sure your password is at least %d characters long. This is a requirement for FIPS builds.", + HMAC_FIPS_MIN_KEY); + } return -1; + } return 0; } @@ -409,8 +427,11 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) } +#ifndef CONFIG_FIPS +#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) { +#ifdef HAVE_AES_KEYWRAP int ret; if (TEST_FAIL()) @@ -419,12 +440,16 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8, NULL); return ret != (n + 1) * 8 ? -1 : 0; +#else /* HAVE_AES_KEYWRAP */ + return -1; +#endif /* HAVE_AES_KEYWRAP */ } int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) { +#ifdef HAVE_AES_KEYWRAP int ret; if (TEST_FAIL()) @@ -433,7 +458,12 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8, NULL); return ret != n * 8 ? -1 : 0; +#else /* HAVE_AES_KEYWRAP */ + return -1; +#endif /* HAVE_AES_KEYWRAP */ } +#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */ +#endif /* CONFIG_FIPS */ #ifndef CONFIG_NO_RC4 @@ -670,6 +700,7 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) != 0) goto done; + priv_sz = pub_sz = RFC3526_LEN; if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz, wpabuf_mhead(pubkey), &pub_sz) != 0) goto done; @@ -803,6 +834,7 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0) goto done; + priv_sz = pub_sz = prime_len; if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz) != 0) goto done; @@ -919,7 +951,8 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, goto done; } - if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0) + if (wc_HmacInit(&hash->hmac, NULL, INVALID_DEVID) != 0 || + wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0) goto done; ret = hash; @@ -1634,35 +1667,21 @@ struct crypto_bignum * crypto_ec_point_compute_y_sqr(struct crypto_ec *e, const struct crypto_bignum *x) { - mp_int *y2 = NULL; - mp_int t; - int calced = 0; + mp_int *y2; if (TEST_FAIL()) return NULL; - if (mp_init(&t) != MP_OKAY) - return NULL; - + /* y^2 = x^3 + ax + b = (x^2 + a)x + b */ y2 = (mp_int *) crypto_bignum_init(); - if (!y2) - goto done; - - if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 || + if (!y2 || + mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 || + mp_addmod(y2, &e->a, &e->prime, y2) != 0 || mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 || - mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 || - mp_addmod(y2, &t, &e->prime, y2) != 0 || - mp_addmod(y2, &e->b, &e->prime, y2) != 0) - goto done; - - calced = 1; -done: - if (!calced) { - if (y2) { - mp_clear(y2); - os_free(y2); - } - mp_clear(&t); + mp_addmod(y2, &e->b, &e->prime, y2) != 0) { + mp_clear(y2); + os_free(y2); + y2 = NULL; } return (struct crypto_bignum *) y2; @@ -1694,33 +1713,37 @@ int crypto_ec_point_cmp(const struct crypto_ec *e, struct crypto_ecdh { struct crypto_ec *ec; + WC_RNG rng; }; struct crypto_ecdh * crypto_ecdh_init(int group) { struct crypto_ecdh *ecdh = NULL; - WC_RNG rng; int ret; - if (wc_InitRng(&rng) != 0) - goto fail; - ecdh = os_zalloc(sizeof(*ecdh)); if (!ecdh) goto fail; + if (wc_InitRng(&ecdh->rng) != 0) + goto fail; + ecdh->ec = crypto_ec_init(group); if (!ecdh->ec) goto fail; - ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key, - ecdh->ec->key.dp->id); + ret = wc_ecc_make_key_ex(&ecdh->rng, ecdh->ec->key.dp->size, + &ecdh->ec->key, ecdh->ec->key.dp->id); if (ret < 0) goto fail; -done: - wc_FreeRng(&rng); +#if defined(ECC_TIMING_RESISTANT) && !defined(CONFIG_FIPS) + ret = wc_ecc_set_rng(&ecdh->ec->key, &ecdh->rng); + if (ret < 0) + goto fail; +#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */ +done: return ecdh; fail: crypto_ecdh_deinit(ecdh); @@ -1733,6 +1756,7 @@ void crypto_ecdh_deinit(struct crypto_ecdh *ecdh) { if (ecdh) { crypto_ec_deinit(ecdh->ec); + wc_FreeRng(&ecdh->rng); os_free(ecdh); } } @@ -1822,4 +1846,266 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh) return crypto_ec_prime_len(ecdh->ec); } + +struct crypto_ec_key { + ecc_key *eckey; + WC_RNG *rng; /* Needs to be initialized before use. + * *NOT* initialized in crypto_ec_key_init */ +}; + + +static struct crypto_ec_key * crypto_ec_key_init(void) +{ + struct crypto_ec_key *key; + + key = os_zalloc(sizeof(struct crypto_ec_key)); + if (key) { +#ifdef CONFIG_FIPS + key->eckey = os_zalloc(sizeof(ecc_key)); +#else /* CONFIG_FIPS */ + key->eckey = wc_ecc_key_new(NULL); +#endif /* CONFIG_FIPS */ + /* Omit key->rng initialization because it seeds itself and thus + * consumes entropy that may never be used. Lazy initialize when + * necessary. */ + if (!key->eckey) { + wpa_printf(MSG_ERROR, + "wolfSSL: crypto_ec_key_init() failed"); + crypto_ec_key_deinit(key); + key = NULL; + } +#ifdef CONFIG_FIPS + else if (wc_ecc_init_ex(key->eckey, NULL, INVALID_DEVID) != 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_init_ex failed"); + crypto_ec_key_deinit(key); + key = NULL; + } +#endif /* CONFIG_FIPS */ + } + return key; +} + + +void crypto_ec_key_deinit(struct crypto_ec_key *key) +{ + if (key) { +#ifdef CONFIG_FIPS + os_free(key->rng); + os_free(key->eckey); +#else /* CONFIG_FIPS */ + wc_rng_free(key->rng); + wc_ecc_key_free(key->eckey); +#endif /* CONFIG_FIPS */ + os_free(key); + } +} + + +struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len) +{ + struct crypto_ec_key *ret; + word32 idx = 0; + + ret = crypto_ec_key_init(); + if (!ret) { + wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed"); + goto fail; + } + + if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) != + 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed"); + goto fail; + } + + return ret; +fail: + if (ret) + crypto_ec_key_deinit(ret); + return NULL; +} + + +int crypto_ec_key_group(struct crypto_ec_key *key) +{ + + if (!key || !key->eckey || !key->eckey->dp) { + wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters", + __func__); + return -1; + } + + switch (key->eckey->dp->id) { + case ECC_SECP256R1: + return 19; + case ECC_SECP384R1: + return 20; + case ECC_SECP521R1: + return 21; + case ECC_BRAINPOOLP256R1: + return 28; + case ECC_BRAINPOOLP384R1: + return 29; + case ECC_BRAINPOOLP512R1: + return 30; + } + + wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key", + key->eckey->dp->id); + return -1; +} + + +struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key) +{ + byte *der = NULL; + int der_len; + struct wpabuf *ret = NULL; + + if (!key || !key->eckey) { + wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters", + __func__); + goto fail; + } + + der_len = wc_EccPublicKeyDerSize(key->eckey, 1); + if (der_len <= 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed"); + goto fail; + } + + der = os_malloc(der_len); + if (!der) + goto fail; + + der_len = wc_EccPublicKeyToDer(key->eckey, der, der_len, 1); + if (der_len <= 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyToDer failed"); + goto fail; + } + + ret = wpabuf_alloc_copy(der, der_len); + os_free(der); + return ret; + +fail: + os_free(der); + return NULL; +} + + +struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len) +{ + word32 idx = 0; + struct crypto_ec_key *ret = NULL; + + ret = crypto_ec_key_init(); + if (!ret) { + wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed"); + goto fail; + } + + if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0) + { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed"); + goto fail; + } + + return ret; +fail: + crypto_ec_key_deinit(ret); + return NULL; +} + + +struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, + size_t len) +{ + byte *der = NULL; + int der_len; + word32 w32_der_len; + struct wpabuf *ret = NULL; + + if (!key || !key->eckey || !data || len == 0) { + wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters", + __func__); + goto fail; + } + + if (!key->rng) { + /* Lazy init key->rng */ +#ifdef CONFIG_FIPS + key->rng = os_zalloc(sizeof(WC_RNG)); +#else /* CONFIG_FIPS */ + key->rng = wc_rng_new(NULL, 0, NULL); +#endif /* CONFIG_FIPS */ + if (!key->rng) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_rng_new failed"); + goto fail; + } +#ifdef CONFIG_FIPS + if (wc_InitRng(key->rng) != 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_InitRng failed"); + goto fail; + } +#endif /* CONFIG_FIPS */ + } + + der_len = wc_ecc_sig_size(key->eckey); + if (der_len <= 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed"); + goto fail; + } + + der = os_malloc(der_len); + if (!der) + goto fail; + + w32_der_len = (word32) der_len; + if (wc_ecc_sign_hash(data, len, der, &w32_der_len, key->rng, key->eckey) + != 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sign_hash failed"); + goto fail; + } + + ret = wpabuf_alloc_copy(der, der_len); + os_free(der); + if (!ret) + wpa_printf(MSG_ERROR, "wolfSSL: wpabuf_alloc_copy failed"); + return ret; +fail: + os_free(der); + return NULL; +} + + +int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data, + size_t len, const u8 *sig, size_t sig_len) +{ + int res = 0; + + if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) { + wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters", + __func__); + return -1; + } + + if (wc_ecc_verify_hash(sig, sig_len, data, len, &res, key->eckey) != 0) + { + wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_verify_hash failed"); + return -1; + } + + if (res != 1) + wpa_printf(MSG_DEBUG, + "wolfSSL: crypto_ec_key_verify_signature failed"); + + return res; +} + #endif /* CONFIG_ECC */ + + +void crypto_unload(void) +{ +} diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c index 8effe2fe..d2bdc95e 100644 --- a/src/crypto/sha1-pbkdf2.c +++ b/src/crypto/sha1-pbkdf2.c @@ -50,6 +50,8 @@ static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid, for (j = 0; j < SHA1_MAC_LEN; j++) digest[j] ^= tmp2[j]; } + forced_memzero(tmp, SHA1_MAC_LEN); + forced_memzero(tmp2, SHA1_MAC_LEN); return 0; } @@ -87,6 +89,7 @@ int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, pos += plen; left -= plen; } + forced_memzero(digest, SHA1_MAC_LEN); return 0; } diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 09fb73b1..7a2ee32d 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -22,7 +22,8 @@ enum tls_event { TLS_CERT_CHAIN_SUCCESS, TLS_CERT_CHAIN_FAILURE, TLS_PEER_CERTIFICATE, - TLS_ALERT + TLS_ALERT, + TLS_UNSAFE_RENEGOTIATION_DISABLED, }; /* @@ -112,6 +113,7 @@ struct tls_config { #define TLS_CONN_ENABLE_TLSv1_1 BIT(15) #define TLS_CONN_ENABLE_TLSv1_2 BIT(16) #define TLS_CONN_TEAP_ANON_DH BIT(17) +#define TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION BIT(18) /** * struct tls_connection_params - Parameters for TLS connection @@ -148,8 +150,6 @@ struct tls_config { * @private_key_passwd: Passphrase for decrypted private key, %NULL if no * passphrase is used. * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used - * @dh_blob: dh_file as inlined data or %NULL if not used - * @dh_blob_len: dh_blob length * @engine: 1 = use engine (e.g., a smartcard) for private key operations * (this is OpenSSL specific for now) * @engine_id: engine id string (this is OpenSSL specific for now) @@ -198,8 +198,6 @@ struct tls_connection_params { const char *private_key_passwd; const char *private_key_passwd2; const char *dh_file; - const u8 *dh_blob; - size_t dh_blob_len; /* OpenSSL specific variables */ int engine; diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index daa01d9e..e3f5b5a4 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -1766,6 +1766,7 @@ int tls_get_library_version(char *buf, size_t buf_len) void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { + wpabuf_free(data); } diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 8095b43b..f3e05ce3 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -281,13 +281,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, - params->dh_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); - tlsv1_cred_free(cred); - return -1; - } - if (tlsv1_client_set_cred(conn->client, cred) < 0) { tlsv1_cred_free(cred); return -1; @@ -342,8 +335,7 @@ int tls_global_set_params(void *tls_ctx, return -1; } - if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, - params->dh_blob_len)) { + if (tlsv1_set_dhparams(cred, params->dh_file, NULL, 0)) { wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); return -1; } @@ -791,6 +783,7 @@ int tls_get_library_version(char *buf, size_t buf_len) void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { + wpabuf_free(data); } diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index 6d6fb0ca..87f45f88 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -212,6 +212,7 @@ int tls_get_library_version(char *buf, size_t buf_len) void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { + wpabuf_free(data); } diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index ba3ef800..a1b51662 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -7,6 +7,9 @@ */ #include "includes.h" +#ifdef CONFIG_TESTING_OPTIONS +#include +#endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_SMARTCARD #ifndef OPENSSL_NO_ENGINE @@ -24,14 +27,21 @@ #ifndef OPENSSL_NO_ENGINE #include #endif /* OPENSSL_NO_ENGINE */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#include +#else /* OpenSSL version >= 3.0 */ #ifndef OPENSSL_NO_DSA #include #endif #ifndef OPENSSL_NO_DH #include #endif +#endif /* OpenSSL version >= 3.0 */ #include "common.h" +#include "utils/list.h" #include "crypto.h" #include "sha1.h" #include "sha256.h" @@ -65,9 +75,7 @@ typedef int stack_index_t; #endif /* OPENSSL_NO_TLSEXT */ #endif /* SSL_set_tlsext_status_type */ -#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \ +#if OPENSSL_VERSION_NUMBER < 0x10100000L && \ !defined(BORINGSSL_API_VERSION) /* * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL @@ -111,17 +119,7 @@ static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) -#ifdef CONFIG_SUITEB -static int RSA_bits(const RSA *r) -{ - return BN_num_bits(r->n); -} -#endif /* CONFIG_SUITEB */ - - +#if OPENSSL_VERSION_NUMBER < 0x10100000L static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) { return ASN1_STRING_data((ASN1_STRING *) x); @@ -234,12 +232,18 @@ static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx, static int tls_openssl_ref_count = 0; static int tls_ex_idx_session = -1; +struct tls_session_data { + struct dl_list list; + struct wpabuf *buf; +}; + struct tls_context { void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); void *cb_ctx; int cert_in_cb; char *ocsp_stapling_response; + struct dl_list sessions; /* struct tls_session_data */ }; static struct tls_context *tls_global = NULL; @@ -307,6 +311,7 @@ static struct tls_context * tls_context_new(const struct tls_config *conf) struct tls_context *context = os_zalloc(sizeof(*context)); if (context == NULL) return NULL; + dl_list_init(&context->sessions); if (conf) { context->event_cb = conf->event_cb; context->cb_ctx = conf->cb_ctx; @@ -958,21 +963,53 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) #endif /* OPENSSL_NO_ENGINE */ +static struct tls_session_data * get_session_data(struct tls_context *context, + const struct wpabuf *buf) +{ + struct tls_session_data *data; + + dl_list_for_each(data, &context->sessions, struct tls_session_data, + list) { + if (data->buf == buf) + return data; + } + + return NULL; +} + + static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess) { struct wpabuf *buf; + struct tls_context *context; + struct tls_session_data *found; + + wpa_printf(MSG_DEBUG, + "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess, + tls_ex_idx_session); if (tls_ex_idx_session < 0) return; buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); if (!buf) return; + + context = SSL_CTX_get_app_data(ctx); + SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); + found = get_session_data(context, buf); + if (!found) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Do not free application session data %p (sess %p)", + buf, sess); + return; + } + + dl_list_del(&found->list); + os_free(found); wpa_printf(MSG_DEBUG, "OpenSSL: Free application session data %p (sess %p)", buf, sess); wpabuf_free(buf); - - SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); } @@ -1019,9 +1056,7 @@ void * tls_init(const struct tls_config *conf) } #endif /* OPENSSL_FIPS */ #endif /* CONFIG_FIPS */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_load_error_strings(); SSL_library_init(); #ifndef OPENSSL_NO_SHA256 @@ -1098,8 +1133,19 @@ void * tls_init(const struct tls_config *conf) SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER); SSL_CTX_set_timeout(ssl, data->tls_session_lifetime); SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb); +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER) && \ + !defined(OPENSSL_IS_BORINGSSL) + /* One session ticket is sufficient for EAP-TLS */ + SSL_CTX_set_num_tickets(ssl, 1); +#endif } else { SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF); +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER) && \ + !defined(OPENSSL_IS_BORINGSSL) + SSL_CTX_set_num_tickets(ssl, 0); +#endif } if (tls_ex_idx_session < 0) { @@ -1148,18 +1194,30 @@ void tls_deinit(void *ssl_ctx) struct tls_data *data = ssl_ctx; SSL_CTX *ssl = data->ssl; struct tls_context *context = SSL_CTX_get_app_data(ssl); + struct tls_session_data *sess_data; + + if (data->tls_session_lifetime > 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions"); + SSL_CTX_flush_sessions(ssl, 0); + wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done"); + } + while ((sess_data = dl_list_first(&context->sessions, + struct tls_session_data, list))) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Freeing not-flushed session data %p", + sess_data->buf); + wpabuf_free(sess_data->buf); + dl_list_del(&sess_data->list); + os_free(sess_data); + } if (context != tls_global) os_free(context); - if (data->tls_session_lifetime > 0) - SSL_CTX_flush_sessions(ssl, 0); os_free(data->ca_cert); SSL_CTX_free(ssl); tls_openssl_ref_count--; if (tls_openssl_ref_count == 0) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); #endif /* OPENSSL_NO_ENGINE */ @@ -1561,6 +1619,63 @@ static void tls_msg_cb(int write_p, int version, int content_type, } +#ifdef CONFIG_TESTING_OPTIONS +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) +/* + * By setting the environment variable SSLKEYLOGFILE to a filename keying + * material will be exported that you may use with Wireshark to decode any + * TLS flows. Please see the following for more details: + * + * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption + * + * Example logging sessions are (you should delete the file on each run): + * + * rm -f /tmp/sslkey.log + * env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ... + * + * rm -f /tmp/sslkey.log + * env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ... + * + * rm -f /tmp/sslkey.log + * env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ... + */ +static void tls_keylog_cb(const SSL *ssl, const char *line) +{ + int fd; + const char *filename; + struct iovec iov[2]; + + filename = getenv("SSLKEYLOGFILE"); + if (!filename) + return; + + fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); + if (fd < 0) { + wpa_printf(MSG_ERROR, + "OpenSSL: Failed to open keylog file %s: %s", + filename, strerror(errno)); + return; + } + + /* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed + * to be atomic for O_APPEND. */ + iov[0].iov_base = (void *) line; + iov[0].iov_len = os_strlen(line); + iov[1].iov_base = "\n"; + iov[1].iov_len = 1; + + if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Failed to write to keylog file %s: %s", + filename, strerror(errno)); + } + + close(fd); +} +#endif +#endif /* CONFIG_TESTING_OPTIONS */ + + struct tls_connection * tls_connection_init(void *ssl_ctx) { struct tls_data *data = ssl_ctx; @@ -1618,6 +1733,14 @@ struct tls_connection * tls_connection_init(void *ssl_ctx) SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); #endif +#ifdef CONFIG_TESTING_OPTIONS +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) + /* Set the keylog file if the admin requested it. */ + if (getenv("SSLKEYLOGFILE")) + SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb); +#endif +#endif /* CONFIG_TESTING_OPTIONS */ + conn->ssl_in = BIO_new(BIO_s_mem()); if (!conn->ssl_in) { tls_show_errors(MSG_INFO, __func__, @@ -2560,16 +2683,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) #ifdef CONFIG_SUITEB if (conn->flags & TLS_CONN_SUITEB) { EVP_PKEY *pk; - RSA *rsa; int len = -1; pk = X509_get_pubkey(err_cert); if (pk) { - rsa = EVP_PKEY_get1_RSA(pk); - if (rsa) { - len = RSA_bits(rsa); - RSA_free(rsa); - } + len = EVP_PKEY_bits(pk); EVP_PKEY_free(pk); } @@ -2960,7 +3078,6 @@ static int tls_connection_set_subject_match(struct tls_connection *conn, #ifdef CONFIG_SUITEB -#if OPENSSL_VERSION_NUMBER >= 0x10002000L static int suiteb_cert_cb(SSL *ssl, void *arg) { struct tls_connection *conn = arg; @@ -2987,7 +3104,6 @@ static int suiteb_cert_cb(SSL *ssl, void *arg) conn->server_dh_prime_len); return 0; } -#endif /* OPENSSL_VERSION_NUMBER */ #endif /* CONFIG_SUITEB */ @@ -3003,6 +3119,11 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, SSL_clear_options(ssl, SSL_OP_NO_TICKET); #endif /* SSL_OP_NO_TICKET */ +#ifdef SSL_OP_LEGACY_SERVER_CONNECT + if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION) + SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT); +#endif /* SSL_OP_LEGACY_SERVER_CONNECT */ + #ifdef SSL_OP_NO_TLSv1 if (flags & TLS_CONN_DISABLE_TLSv1_0) SSL_set_options(ssl, SSL_OP_NO_TLSv1); @@ -3082,7 +3203,6 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, /* Start with defaults from BoringSSL */ SSL_set_verify_algorithm_prefs(conn->ssl, NULL, 0); #endif /* OPENSSL_IS_BORINGSSL */ -#if OPENSSL_VERSION_NUMBER >= 0x10002000L if (flags & TLS_CONN_SUITEB_NO_ECDH) { const char *ciphers = "DHE-RSA-AES256-GCM-SHA384"; @@ -3098,7 +3218,9 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, return -1; } } else if (flags & TLS_CONN_SUITEB) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L EC_KEY *ecdh; +#endif const char *ciphers = "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384"; int nid[1] = { NID_secp384r1 }; @@ -3115,6 +3237,14 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, return -1; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (SSL_set1_groups(ssl, nid, 1) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to set Suite B groups"); + return -1; + } + +#else if (SSL_set1_curves(ssl, nid, 1) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set Suite B curves"); @@ -3129,6 +3259,7 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, return -1; } EC_KEY_free(ecdh); +#endif } if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) { #ifdef OPENSSL_IS_BORINGSSL @@ -3153,13 +3284,6 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, SSL_set_options(ssl, SSL_OP_NO_TLSv1_1); SSL_set_cert_cb(ssl, suiteb_cert_cb, conn); } -#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */ - if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) { - wpa_printf(MSG_ERROR, - "OpenSSL: Suite B RSA case not supported with this OpenSSL version"); - return -1; - } -#endif /* OPENSSL_VERSION_NUMBER */ #ifdef OPENSSL_IS_BORINGSSL if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) { @@ -3293,14 +3417,14 @@ static int tls_connection_client_cert(struct tls_connection *conn, return 0; #ifdef PKCS12_FUNCS -#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER) +#ifdef LIBRESSL_VERSION_NUMBER /* * Clear previously set extra chain certificates, if any, from PKCS#12 - * processing in tls_parse_pkcs12() to allow OpenSSL to build a new + * processing in tls_parse_pkcs12() to allow LibreSSL to build a new * chain properly. */ SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx); -#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */ +#endif /* LIBRESSL_VERSION_NUMBER */ #endif /* PKCS12_FUNCS */ if (client_cert_blob && @@ -3493,7 +3617,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, } if (certs) { -#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) +#ifndef LIBRESSL_VERSION_NUMBER if (ssl) SSL_clear_chain_certs(ssl); else @@ -3542,7 +3666,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, * the extra certificates not to be required. */ res = 0; -#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ +#else /* LIBRESSL_VERSION_NUMBER */ SSL_CTX_clear_extra_chain_certs(data->ssl); while ((cert = sk_X509_pop(certs)) != NULL) { X509_NAME_oneline(X509_get_subject_name(cert), buf, @@ -3561,7 +3685,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, } } sk_X509_pop_free(certs, X509_free); -#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ +#endif /* LIBRSESSL_VERSION_NUMBER */ } PKCS12_free(p12); @@ -3862,6 +3986,7 @@ static int tls_connection_private_key(struct tls_data *data, } #endif /* OPENSSL_NO_EC */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, (u8 *) private_key_blob, private_key_blob_len) == 1) { @@ -3870,6 +3995,7 @@ static int tls_connection_private_key(struct tls_data *data, ok = 1; break; } +#endif bio = BIO_new_mem_buf((u8 *) private_key_blob, private_key_blob_len); @@ -3977,79 +4103,44 @@ static int tls_global_private_key(struct tls_data *data, } -static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) -{ -#ifdef OPENSSL_NO_DH - if (dh_file == NULL) - return 0; - wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " - "dh_file specified"); - return -1; -#else /* OPENSSL_NO_DH */ - DH *dh; - BIO *bio; - - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (conn == NULL) - return -1; - - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", - dh_file, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#ifndef OPENSSL_NO_DH #ifndef OPENSSL_NO_DSA - while (dh == NULL) { - DSA *dsa; - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" - " trying to parse as DSA params", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) - break; - dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); - BIO_free(bio); - if (!dsa) { - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " - "'%s': %s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - break; - } +/* This is needed to replace the deprecated DSA_dup_DH() function */ +static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa) +{ + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + BIGNUM *p = NULL, *q = NULL, *g = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; - wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " - "params into DH params"); - break; - } - break; - } -#endif /* !OPENSSL_NO_DSA */ - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " - "'%s'", dh_file); - return -1; - } + if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) || + !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) || + !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) || + !(bld = OSSL_PARAM_BLD_new()) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) || + !(params = OSSL_PARAM_BLD_to_param(bld)) || + !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) || + EVP_PKEY_fromdata_init(ctx) != 1 || + EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS, + params) != 1) + wpa_printf(MSG_INFO, + "TLS: Failed to convert DSA parameters to DH parameters"); - if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { - wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " - "%s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - DH_free(dh); - return -1; - } - DH_free(dh); - return 0; -#endif /* OPENSSL_NO_DH */ + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + BN_free(p); + BN_free(q); + BN_free(g); + return pkey; } - +#endif /* !OPENSSL_NO_DSA */ +#endif /* OPENSSL_NO_DH */ +#endif /* OpenSSL version >= 3.0 */ static int tls_global_dh(struct tls_data *data, const char *dh_file) { @@ -4060,15 +4151,88 @@ static int tls_global_dh(struct tls_data *data, const char *dh_file) "dh_file specified"); return -1; #else /* OPENSSL_NO_DH */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + SSL_CTX *ssl_ctx = data->ssl; + BIO *bio; + OSSL_DECODER_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL, *tmpkey = NULL; + bool dsa = false; + + if (!ssl_ctx) + return -1; + if (!dh_file) { + SSL_CTX_set_dh_auto(ssl_ctx, 1); + return 0; + } + + bio = BIO_new_file(dh_file, "r"); + if (!bio) { + wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + ctx = OSSL_DECODER_CTX_new_for_pkey( + &tmpkey, "PEM", NULL, NULL, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL); + if (!ctx || + OSSL_DECODER_from_bio(ctx, bio) != 1) { + wpa_printf(MSG_INFO, + "TLS: Failed to decode domain parameters from '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); + BIO_free(bio); + return -1; + } + BIO_free(bio); + + if (!tmpkey) { + wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters"); + return -1; + } + +#ifndef OPENSSL_NO_DSA + if (EVP_PKEY_is_a(tmpkey, "DSA")) { + pkey = openssl_dsa_to_dh(tmpkey); + EVP_PKEY_free(tmpkey); + if (!pkey) + return -1; + dsa = true; + } +#endif /* !OPENSSL_NO_DSA */ + if (!dsa) { + if (EVP_PKEY_is_a(tmpkey, "DH") || + EVP_PKEY_is_a(tmpkey, "DHX")) { + } else { + wpa_printf(MSG_INFO, + "TLS: No DH parameters found in %s", + dh_file); + EVP_PKEY_free(tmpkey); + return -1; + } + pkey = tmpkey; + tmpkey = NULL; + } + + if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) { + wpa_printf(MSG_INFO, + "TLS: Failed to set DH params from '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(pkey); + return -1; + } + return 0; +#else /* OpenSSL version >= 3.0 */ SSL_CTX *ssl_ctx = data->ssl; DH *dh; BIO *bio; - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (ssl_ctx == NULL) + if (!ssl_ctx) return -1; + if (!dh_file) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) + SSL_CTX_set_dh_auto(ssl_ctx, 1); +#endif + return 0; + } bio = BIO_new_file(dh_file, "r"); if (bio == NULL) { @@ -4122,6 +4286,7 @@ static int tls_global_dh(struct tls_data *data, const char *dh_file) } DH_free(dh); return 0; +#endif /* OpenSSL version >= 3.0 */ #endif /* OPENSSL_NO_DH */ } @@ -4152,9 +4317,7 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, #ifdef OPENSSL_NEED_EAP_FAST_PRF static int openssl_get_keyblock_size(SSL *ssl) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L const EVP_CIPHER *c; const EVP_MD *h; int md_size; @@ -4322,6 +4485,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, static struct wpabuf * openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data) { + struct tls_context *context = conn->context; int res; struct wpabuf *out_data; @@ -4351,7 +4515,19 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data) wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " "write"); else { + unsigned long error = ERR_peek_last_error(); + tls_show_errors(MSG_INFO, __func__, "SSL_connect"); + + if (context->event_cb && + ERR_GET_LIB(error) == ERR_LIB_SSL && + ERR_GET_REASON(error) == + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) { + context->event_cb( + context->cb_ctx, + TLS_UNSAFE_RENEGOTIATION_DISABLED, + NULL); + } conn->failed++; if (!conn->server && !conn->client_hello_generated) { /* The server would not understand TLS Alert @@ -4374,8 +4550,6 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data) if ((conn->flags & TLS_CONN_SUITEB) && !conn->server && os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 && conn->server_dh_prime_len < 3072) { - struct tls_context *context = conn->context; - /* * This should not be reached since earlier cert_cb should have * terminated the handshake. Keep this check here for extra @@ -4867,6 +5041,21 @@ static int ocsp_resp_cb(SSL *s, void *arg) len = SSL_get_tlsext_status_ocsp_resp(s, &p); if (!p) { +#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L + if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) { + /* TLS 1.3 sends the OCSP response with the server + * Certificate message. Since that Certificate message + * is not sent when resuming a session, there can be no + * new OCSP response. Allow this since the OCSP response + * was validated when checking the initial certificate + * exchange. */ + wpa_printf(MSG_DEBUG, + "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session"); + return 1; + } +#endif +#endif wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; } @@ -5268,12 +5457,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - if (tls_connection_dh(conn, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", - params->dh_file); - return -1; - } - ciphers = params->openssl_ciphers; #ifdef CONFIG_SUITEB #ifdef OPENSSL_IS_BORINGSSL @@ -5295,22 +5478,21 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, if (!params->openssl_ecdh_curves) { #ifndef OPENSSL_IS_BORINGSSL #ifndef OPENSSL_NO_EC -#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \ - (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set ECDH curves to auto"); return -1; } -#endif /* >= 1.0.2 && < 1.1.0 */ +#endif /* < 1.1.0 */ #endif /* OPENSSL_NO_EC */ #endif /* OPENSSL_IS_BORINGSSL */ } else if (params->openssl_ecdh_curves[0]) { -#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L) +#ifdef OPENSSL_IS_BORINGSSL wpa_printf(MSG_INFO, - "OpenSSL: ECDH configuration nnot supported"); + "OpenSSL: ECDH configuration not supported"); return -1; -#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */ +#else /* !OPENSSL_IS_BORINGSSL */ #ifndef OPENSSL_NO_EC if (SSL_set1_curves_list(conn->ssl, params->openssl_ecdh_curves) != 1) { @@ -5520,22 +5702,21 @@ int tls_global_set_params(void *tls_ctx, if (!params->openssl_ecdh_curves) { #ifndef OPENSSL_IS_BORINGSSL #ifndef OPENSSL_NO_EC -#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \ - (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set ECDH curves to auto"); return -1; } -#endif /* >= 1.0.2 && < 1.1.0 */ +#endif /* < 1.1.0 */ #endif /* OPENSSL_NO_EC */ #endif /* OPENSSL_IS_BORINGSSL */ } else if (params->openssl_ecdh_curves[0]) { -#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L) +#ifdef OPENSSL_IS_BORINGSSL wpa_printf(MSG_INFO, - "OpenSSL: ECDH configuration nnot supported"); + "OpenSSL: ECDH configuration not supported"); return -1; -#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */ +#else /* !OPENSSL_IS_BORINGSSL */ #ifndef OPENSSL_NO_EC #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_CTX_set_ecdh_auto(ssl_ctx, 1); @@ -5597,9 +5778,7 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, struct tls_connection *conn = arg; int ret; -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (conn == NULL || conn->session_ticket_cb == NULL) return 0; @@ -5710,6 +5889,7 @@ void tls_connection_set_success_data(struct tls_connection *conn, { SSL_SESSION *sess; struct wpabuf *old; + struct tls_session_data *sess_data = NULL; if (tls_ex_idx_session < 0) goto fail; @@ -5718,20 +5898,35 @@ void tls_connection_set_success_data(struct tls_connection *conn, goto fail; old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); if (old) { - wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p", - old); - wpabuf_free(old); + struct tls_session_data *found; + + found = get_session_data(conn->context, old); + wpa_printf(MSG_DEBUG, + "OpenSSL: Replacing old success data %p (sess %p)%s", + old, sess, found ? "" : " (not freeing)"); + if (found) { + dl_list_del(&found->list); + os_free(found); + wpabuf_free(old); + } } - if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) + + sess_data = os_zalloc(sizeof(*sess_data)); + if (!sess_data || + SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) goto fail; - wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data); + sess_data->buf = data; + dl_list_add(&conn->context->sessions, &sess_data->list); + wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)", + data, sess); conn->success_data = 1; return; fail: wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data"); wpabuf_free(data); + os_free(sess_data); } diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c index 97bf605b..b570bea0 100644 --- a/src/crypto/tls_openssl_ocsp.c +++ b/src/crypto/tls_openssl_ocsp.c @@ -644,13 +644,12 @@ enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert, buf); ctx = X509_STORE_CTX_new(); - if (!ctx || - !X509_STORE_CTX_init(ctx, store, signer, untrusted) || - !X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER)) { + if (!ctx || !X509_STORE_CTX_init(ctx, store, signer, untrusted)) goto fail; - } + X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER); ret = X509_verify_cert(ctx); chain = X509_STORE_CTX_get1_chain(ctx); + X509_STORE_CTX_cleanup(ctx); if (ret <= 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Could not validate OCSP signer certificate"); @@ -663,6 +662,7 @@ enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert, } if (!signer_trusted) { + X509_check_purpose(signer, -1, 0); if ((X509_get_extension_flags(signer) & EXFLAG_XKUSAGE) && (X509_get_extended_key_usage(signer) & XKU_OCSP_SIGN)) { wpa_printf(MSG_DEBUG, diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c index cf482bfc..b4f1bbe7 100644 --- a/src/crypto/tls_wolfssl.c +++ b/src/crypto/tls_wolfssl.c @@ -26,6 +26,10 @@ #include #endif +#ifdef CONFIG_FIPS +#include +#endif /* CONFIG_FIPS */ + #if !defined(CONFIG_FIPS) && \ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \ defined(EAP_SERVER_FAST)) @@ -58,6 +62,7 @@ struct tls_context { void *cb_ctx; int cert_in_cb; char *ocsp_stapling_response; + unsigned int tls_session_lifetime; }; static struct tls_context *tls_global = NULL; @@ -94,6 +99,7 @@ struct tls_connection { WOLFSSL_X509 *peer_cert; WOLFSSL_X509 *peer_issuer; WOLFSSL_X509 *peer_issuer_issuer; + char *peer_subject; /* peer subject info for authenticated peer */ }; @@ -190,6 +196,33 @@ static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess) } +#if defined(CONFIG_FIPS) && defined(HAVE_FIPS) +static void wcFipsCb(int ok, int err, const char *hash) +{ + wpa_printf(MSG_INFO, + "wolfFIPS: wolfCrypt Fips error callback, ok = %d, err = %d", + ok, err); + wpa_printf(MSG_INFO, "wolfFIPS: message = %s", wc_GetErrorString(err)); + wpa_printf(MSG_INFO, "wolfFIPS: hash = %s", hash); + if (err == IN_CORE_FIPS_E) { + wpa_printf(MSG_ERROR, + "wolfFIPS: In core integrity hash check failure, copy above hash"); + wpa_printf(MSG_ERROR, "wolfFIPS: into verifyCore[] in fips_test.c and rebuild"); + } +} +#endif /* CONFIG_FIPS && HAVE_FIPS */ + + +#ifdef DEBUG_WOLFSSL +static void wolfSSL_logging_cb(const int log_level, + const char * const log_message) +{ + (void) log_level; + wpa_printf(MSG_DEBUG, "wolfSSL log:%s", log_message); +} +#endif /* DEBUG_WOLFSSL */ + + void * tls_init(const struct tls_config *conf) { WOLFSSL_CTX *ssl_ctx; @@ -197,6 +230,7 @@ void * tls_init(const struct tls_config *conf) const char *ciphers; #ifdef DEBUG_WOLFSSL + wolfSSL_SetLoggingCb(wolfSSL_logging_cb); wolfSSL_Debugging_ON(); #endif /* DEBUG_WOLFSSL */ @@ -209,7 +243,9 @@ void * tls_init(const struct tls_config *conf) if (wolfSSL_Init() < 0) return NULL; - /* wolfSSL_Debugging_ON(); */ +#if defined(CONFIG_FIPS) && defined(HAVE_FIPS) + wolfCrypt_SetCb_fips(wcFipsCb); +#endif /* CONFIG_FIPS && HAVE_FIPS */ } tls_ref_count++; @@ -227,17 +263,21 @@ void * tls_init(const struct tls_config *conf) } wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb); wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb); + context->tls_session_lifetime = conf->tls_session_lifetime; wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context); if (conf->tls_session_lifetime > 0) { + wolfSSL_CTX_set_session_id_context(ssl_ctx, + (const unsigned char *) + "hostapd", 7); wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1); wolfSSL_CTX_set_session_cache_mode(ssl_ctx, - SSL_SESS_CACHE_SERVER); + WOLFSSL_SESS_CACHE_SERVER); wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime); wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb); } else { wolfSSL_CTX_set_session_cache_mode(ssl_ctx, - SSL_SESS_CACHE_CLIENT); + WOLFSSL_SESS_CACHE_OFF); } if (conf && conf->openssl_ciphers) @@ -336,6 +376,7 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) os_free(conn->alt_subject_match); os_free(conn->suffix_match); os_free(conn->domain_match); + os_free(conn->peer_subject); /* self */ os_free(conn); @@ -369,10 +410,13 @@ int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) wolfSSL_set_quiet_shutdown(conn->ssl, 1); wolfSSL_shutdown(conn->ssl); - session = wolfSSL_get_session(conn->ssl); - if (wolfSSL_clear(conn->ssl) != 1) + session = wolfSSL_get1_session(conn->ssl); + if (wolfSSL_clear(conn->ssl) != 1) { + wolfSSL_SESSION_free(session); return -1; + } wolfSSL_set_session(conn->ssl, session); + wolfSSL_SESSION_free(session); return 0; } @@ -420,44 +464,6 @@ static int tls_connection_set_subject_match(struct tls_connection *conn, } -static int tls_connection_dh(struct tls_connection *conn, const char *dh_file, - const u8 *dh_blob, size_t blob_len) -{ - if (!dh_file && !dh_blob) - return 0; - - wolfSSL_set_accept_state(conn->ssl); - - if (dh_blob) { - if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len, - SSL_FILETYPE_ASN1) < 0) { - wpa_printf(MSG_INFO, "SSL: use DH DER blob failed"); - return -1; - } - wpa_printf(MSG_DEBUG, "SSL: use DH blob OK"); - return 0; - } - - if (dh_file) { - wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file); - if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, - SSL_FILETYPE_PEM) < 0) { - wpa_printf(MSG_INFO, "SSL: use DH PEM file failed"); - if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, - SSL_FILETYPE_ASN1) < 0) { - wpa_printf(MSG_INFO, - "SSL: use DH DER file failed"); - return -1; - } - } - wpa_printf(MSG_DEBUG, "SSL: use DH file OK"); - return 0; - } - - return 0; -} - - static int tls_connection_client_cert(struct tls_connection *conn, const char *client_cert, const u8 *client_cert_blob, @@ -472,7 +478,13 @@ static int tls_connection_client_cert(struct tls_connection *conn, SSL_FILETYPE_ASN1) != SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use client cert DER blob failed"); - return -1; + if (wolfSSL_use_certificate_chain_buffer_format( + conn->ssl, client_cert_blob, blob_len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, + "SSL: use client cert PEM blob failed"); + return -1; + } } wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK"); return 0; @@ -534,23 +546,35 @@ static int tls_connection_private_key(void *tls_ctx, if (private_key_blob) { if (wolfSSL_use_PrivateKey_buffer(conn->ssl, private_key_blob, blob_len, - SSL_FILETYPE_ASN1) <= 0) { + SSL_FILETYPE_ASN1) != + SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use private DER blob failed"); + if (wolfSSL_use_PrivateKey_buffer( + conn->ssl, + private_key_blob, blob_len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, + "SSL: use private PEM blob failed"); + } else { + ok = 1; + } } else { - wpa_printf(MSG_DEBUG, "SSL: use private key blob OK"); ok = 1; } + if (ok) + wpa_printf(MSG_DEBUG, "SSL: use private key blob OK"); } if (!ok && private_key) { if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_PEM) <= 0) { + SSL_FILETYPE_PEM) != + SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use private key PEM file failed"); if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_ASN1) <= 0) - { + SSL_FILETYPE_ASN1) != + SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use private key DER file failed"); } else { @@ -721,8 +745,7 @@ static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match, WOLFSSL_X509_NAME_ENTRY *e; WOLFSSL_ASN1_STRING *cn; - i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME, - i); + i = wolfSSL_X509_NAME_get_index_by_NID(name, NID_commonName, i); if (i == -1) break; e = wolfSSL_X509_NAME_get_entry(name, i); @@ -1134,6 +1157,11 @@ static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx) context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_SUCCESS, NULL); + if (depth == 0 && preverify_ok) { + os_free(conn->peer_subject); + conn->peer_subject = os_strdup(buf); + } + return preverify_ok; } @@ -1194,8 +1222,14 @@ static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn, if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len, SSL_FILETYPE_ASN1) != SSL_SUCCESS) { - wpa_printf(MSG_INFO, "SSL: failed to load CA blob"); - return -1; + wpa_printf(MSG_INFO, "SSL: failed to load DER CA blob"); + if (wolfSSL_CTX_load_verify_buffer( + ctx, ca_cert_blob, blob_len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, + "SSL: failed to load PEM CA blob"); + return -1; + } } wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK"); return 0; @@ -1238,10 +1272,8 @@ static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn, static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags) { #ifdef HAVE_SESSION_TICKET -#if 0 if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET)) wolfSSL_UseSessionTicket(ssl); -#endif #endif /* HAVE_SESSION_TICKET */ if (flags & TLS_CONN_DISABLE_TLSv1_0) @@ -1250,6 +1282,8 @@ static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags) wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1); if (flags & TLS_CONN_DISABLE_TLSv1_2) wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2); + if (flags & TLS_CONN_DISABLE_TLSv1_3) + wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3); } @@ -1289,12 +1323,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - if (tls_connection_dh(conn, params->dh_file, params->dh_blob, - params->dh_blob_len) < 0) { - wpa_printf(MSG_INFO, "Error setting DH"); - return -1; - } - if (params->openssl_ciphers && wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) { wpa_printf(MSG_INFO, @@ -1311,7 +1339,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, WOLFSSL_CSR_OCSP_USE_NONCE) != SSL_SUCCESS) return -1; - wolfSSL_CTX_EnableOCSP(tls_ctx, 0); + if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS) + return -1; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 @@ -1320,7 +1349,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, WOLFSSL_CSR2_OCSP_MULTI, 0) != SSL_SUCCESS) return -1; - wolfSSL_CTX_EnableOCSP(tls_ctx, 0); + if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS) + return -1; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ #if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \ @@ -1427,25 +1457,10 @@ static int tls_global_private_key(void *ssl_ctx, const char *private_key, } -static int tls_global_dh(void *ssl_ctx, const char *dh_file, - const u8 *dh_blob, size_t blob_len) +static int tls_global_dh(void *ssl_ctx, const char *dh_file) { WOLFSSL_CTX *ctx = ssl_ctx; - if (!dh_file && !dh_blob) - return 0; - - if (dh_blob) { - if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len, - SSL_FILETYPE_ASN1) < 0) { - wpa_printf(MSG_INFO, - "SSL: global use DH DER blob failed"); - return -1; - } - wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK"); - return 0; - } - if (dh_file) { if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) < 0) { @@ -1532,8 +1547,7 @@ int tls_global_set_params(void *tls_ctx, return -1; } - if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob, - params->dh_blob_len) < 0) { + if (tls_global_dh(tls_ctx, params->dh_file) < 0) { wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'", params->dh_file); return -1; @@ -1590,6 +1604,9 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, int verify_peer, unsigned int flags, const u8 *session_ctx, size_t session_ctx_len) { + static int counter = 0; + struct tls_context *context; + if (!conn) return -1; @@ -1607,6 +1624,22 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, wolfSSL_set_accept_state(conn->ssl); + context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0); + if (context && context->tls_session_lifetime == 0) { + /* + * Set session id context to a unique value to make sure + * session resumption cannot be used either through session + * caching or TLS ticket extension. + */ + counter++; + wolfSSL_set_session_id_context(conn->ssl, + (const unsigned char *) &counter, + sizeof(counter)); + } else { + wolfSSL_set_session_id_context(conn->ssl, session_ctx, + session_ctx_len); + } + /* TODO: do we need to fake a session like OpenSSL does here? */ return 0; @@ -1997,11 +2030,21 @@ int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, const char *label, const u8 *context, size_t context_len, u8 *out, size_t out_len) { - if (context) + if (!conn) return -1; - if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0) +#if LIBWOLFSSL_VERSION_HEX >= 0x04007000 + if (wolfSSL_export_keying_material(conn->ssl, out, out_len, + label, os_strlen(label), + context, context_len, + context != NULL) != WOLFSSL_SUCCESS) return -1; return 0; +#else + if (context || + wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0) + return -1; +#endif + return 0; } @@ -2046,9 +2089,15 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, _out, skip + out_len); ret = 0; } else { +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, + "wolfSSL: Can't use sha1_md5 in FIPS build"); + ret = -1; +#else /* CONFIG_FIPS */ ret = tls_prf_sha1_md5(master_key, master_key_len, "key expansion", seed, sizeof(seed), _out, skip + out_len); +#endif /* CONFIG_FIPS */ } forced_memzero(master_key, master_key_len); @@ -2160,6 +2209,39 @@ void tls_connection_remove_session(struct tls_connection *conn) } +int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len) +{ + size_t len; + int reused; + + reused = wolfSSL_session_reused(conn->ssl); + if ((wolfSSL_is_server(conn->ssl) && !reused) || + (!wolfSSL_is_server(conn->ssl) && reused)) + len = wolfSSL_get_peer_finished(conn->ssl, buf, max_len); + else + len = wolfSSL_get_finished(conn->ssl, buf, max_len); + + if (len == 0 || len > max_len) + return -1; + + return len; +} + + +u16 tls_connection_get_cipher_suite(struct tls_connection *conn) +{ + return (u16) wolfSSL_get_current_cipher_suite(conn->ssl); +} + + +const char * tls_connection_get_peer_subject(struct tls_connection *conn) +{ + if (conn) + return conn->peer_subject; + return NULL; +} + + void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { @@ -2206,3 +2288,11 @@ tls_connection_get_success_data(struct tls_connection *conn) return NULL; return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session); } + + +bool tls_connection_get_own_cert_used(struct tls_connection *conn) +{ + if (conn) + return wolfSSL_get_certificate(conn->ssl) != NULL; + return false; +} diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 8b92e129..46cee442 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -200,6 +200,15 @@ struct he_capabilities { u16 he_6ghz_capa; }; +/* struct eht_capabilities - IEEE 802.11be EHT capabilities */ +struct eht_capabilities { + bool eht_supported; + u16 mac_cap; + u8 phy_cap[EHT_PHY_CAPAB_LEN]; + u8 mcs[EHT_MCS_NSS_CAPAB_LEN]; + u8 ppet[EHT_PPE_THRESH_CAPAB_LEN]; +}; + #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) #define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1) @@ -298,6 +307,11 @@ struct hostapd_hw_modes { * for IEEE 802.11ay EDMG configuration. */ struct ieee80211_edmg_config edmg; + + /** + * eht_capab - EHT (IEEE 802.11be) capabilities + */ + struct eht_capabilities eht_capab[IEEE80211_MODE_NUM]; }; @@ -338,6 +352,7 @@ struct hostapd_hw_modes { * @parent_tsf: Time when the Beacon/Probe Response frame was received in terms * of TSF of the BSS specified by %tsf_bssid. * @tsf_bssid: The BSS that %parent_tsf TSF time refers to. + * @beacon_newer: Whether the Beacon frame data is known to be newer * @ie_len: length of the following IE field in octets * @beacon_ie_len: length of the following Beacon IE field in octets * @@ -370,6 +385,7 @@ struct wpa_scan_res { int snr; u64 parent_tsf; u8 tsf_bssid[ETH_ALEN]; + bool beacon_newer; size_t ie_len; size_t beacon_ie_len; /* Followed by ie_len + beacon_ie_len octets of IE data */ @@ -782,6 +798,16 @@ struct hostapd_freq_params { * for IEEE 802.11ay EDMG configuration. */ struct ieee80211_edmg_config edmg; + + /** + * radar_background - Whether radar/CAC background is requested + */ + bool radar_background; + + /** + * eht_enabled - Whether EHT is enabled + */ + bool eht_enabled; }; /** @@ -1036,7 +1062,7 @@ struct wpa_driver_associate_params { * * If the driver needs to do special configuration for WPS association, * this variable provides more information on what type of association - * is being requested. Most drivers should not need ot use this. + * is being requested. Most drivers should not need to use this. */ enum wps_mode wps; @@ -1781,7 +1807,7 @@ enum wpa_driver_if_type { WPA_IF_P2P_GROUP, /** - * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the + * WPA_IF_P2P_DEVICE - P2P Device interface is used to identify the * abstracted P2P Device function in the driver */ WPA_IF_P2P_DEVICE, @@ -2033,6 +2059,10 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL /** Driver expects user space implementation of SME in AP mode */ #define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL +/** Driver handles SA Query procedures in AP mode */ +#define WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP 0x0000000000000200ULL +/** Driver supports background radar/CAC detection */ +#define WPA_DRIVER_RADAR_BACKGROUND 0x0000000000000400ULL u64 flags2; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ @@ -2200,6 +2230,8 @@ struct hostapd_sta_add_params { const struct ieee80211_he_capabilities *he_capab; size_t he_capab_len; const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab; + const struct ieee80211_eht_capabilities *eht_capab; + size_t eht_capab_len; u32 flags; /* bitmask of WPA_STA_* flags */ u32 flags_mask; /* unset bits in flags */ #ifdef CONFIG_MESH @@ -2403,6 +2435,27 @@ struct csa_settings { u16 counter_offset_presp[2]; }; +/** + * struct cca_settings - Settings for color switch command + * @cca_count: Count in Beacon frames (TBTT) to perform the switch + * @cca_color: The new color that we are switching to + * @beacon_cca: Beacon/Probe Response/(Re)Association Response frame info for + * color switch period + * @beacon_after: Next Beacon/Probe Response/(Re)Association Response frame info + * @counter_offset_beacon: Offset to the count field in Beacon frame tail + * @counter_offset_presp: Offset to the count field in Probe Response frame + */ +struct cca_settings { + u8 cca_count; + u8 cca_color; + + struct beacon_data beacon_cca; + struct beacon_data beacon_after; + + u16 counter_offset_beacon; + u16 counter_offset_presp; +}; + /* TDLS peer capabilities for send_tdls_mgmt() */ enum tdls_peer_capability { TDLS_PEER_HT = BIT(0), @@ -2467,6 +2520,9 @@ struct drv_acs_params { /* Indicates whether EDMG is enabled */ int edmg_enabled; + + /* Indicates whether EHT is enabled */ + bool eht_enabled; }; struct wpa_bss_trans_info { @@ -2608,7 +2664,7 @@ struct wpa_driver_ops { * some drivers may expect them in different order than wpa_supplicant * is using. If the TX/RX keys are swapped, all TKIP encrypted packets * will trigger Michael MIC errors. This can be fixed by changing the - * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key + * order of MIC keys by swapping the bytes 16..23 and 24..31 of the key * in driver_*.c set_key() implementation, see driver_ndis.c for an * example on how this can be done. */ @@ -3988,6 +4044,17 @@ struct wpa_driver_ops { */ int (*switch_channel)(void *priv, struct csa_settings *settings); + /** + * switch_color - Announce color switch and migrate the BSS to the + * given color + * @priv: Private driver interface data + * @settings: Settings for CCA period and new color + * Returns: 0 on success, -1 on failure + * + * This function is used to move the BSS to its new color. + */ + int (*switch_color)(void *priv, struct cca_settings *settings); + /** * add_tx_ts - Add traffic stream * @priv: Private driver interface data @@ -4617,7 +4684,7 @@ enum wpa_event_type { * This event must be delivered when a Michael MIC error is detected by * the local driver. Additional data for event processing is * provided with union wpa_event_data::michael_mic_failure. This - * information is used to request new encyption key and to initiate + * information is used to request new encryption key and to initiate * TKIP countermeasures if needed. */ EVENT_MICHAEL_MIC_FAILURE, @@ -5147,6 +5214,26 @@ enum wpa_event_type { * non-zero wait time and that has not been explicitly cancelled. */ EVENT_TX_WAIT_EXPIRE, + + /** + * EVENT_BSS_COLOR_COLLISION - Notification of a BSS color collision + */ + EVENT_BSS_COLOR_COLLISION, + + /** + * EVENT_CCA_STARTED_NOTIFY - Notification that CCA has started + */ + EVENT_CCA_STARTED_NOTIFY, + + /** + * EVENT_CCA_ABORTED_NOTIFY - Notification that CCA has aborted + */ + EVENT_CCA_ABORTED_NOTIFY, + + /** + * EVENT_CCA_NOTIFY - Notification that CCA has completed + */ + EVENT_CCA_NOTIFY, }; @@ -6039,6 +6126,13 @@ union wpa_event_data { struct unprot_beacon { const u8 *sa; } unprot_beacon; + + /** + * struct bss_color_collision - Data for EVENT_BSS_COLOR_COLLISION + */ + struct bss_color_collision { + u64 bitmap; + } bss_color_collision; }; /** diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 9b4166d2..cb66dfa9 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -17,7 +17,6 @@ #include "eloop.h" #include "common/ieee802_11_defs.h" #include "l2_packet/l2_packet.h" -#include "p2p/p2p.h" #include "common.h" #ifndef _BYTE_ORDER diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 741521c6..8db78616 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -91,6 +91,10 @@ const char * event_to_string(enum wpa_event_type event) E2S(UPDATE_DH); E2S(UNPROT_BEACON); E2S(TX_WAIT_EXPIRE); + E2S(BSS_COLOR_COLLISION); + E2S(CCA_STARTED_NOTIFY); + E2S(CCA_ABORTED_NOTIFY); + E2S(CCA_NOTIFY); } return "UNKNOWN"; diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c index 3dba13ce..b609bbf3 100644 --- a/src/drivers/driver_macsec_linux.c +++ b/src/drivers/driver_macsec_linux.c @@ -77,6 +77,9 @@ struct macsec_drv_data { u8 encoding_sa; bool encoding_sa_set; + + u64 cipher_suite; + bool cipher_suite_set; }; @@ -460,8 +463,14 @@ static int macsec_drv_set_replay_protect(void *priv, bool enabled, */ static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs) { + struct macsec_drv_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs); - return 0; + + drv->cipher_suite_set = true; + drv->cipher_suite = cs; + + return try_commit(drv); } @@ -1063,7 +1072,8 @@ static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa) } -static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci) +static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci, + u64 cs) { struct rtnl_link *needle; void *match; @@ -1074,6 +1084,8 @@ static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci) rtnl_link_set_link(needle, parent); rtnl_link_macsec_set_sci(needle, sci); + if (cs) + rtnl_link_macsec_set_cipher_suite(needle, cs); match = nl_cache_find(cache, (struct nl_object *) needle); rtnl_link_put(needle); @@ -1098,6 +1110,7 @@ static int macsec_drv_create_transmit_sc( char *ifname; u64 sci; int err; + u64 cs = 0; wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)", @@ -1122,6 +1135,12 @@ static int macsec_drv_create_transmit_sc( drv->created_link = true; + if (drv->cipher_suite_set) { + cs = drv->cipher_suite; + drv->cipher_suite_set = false; + rtnl_link_macsec_set_cipher_suite(link, cs); + } + err = rtnl_link_add(drv->sk, link, NLM_F_CREATE); if (err == -NLE_BUSY) { wpa_printf(MSG_INFO, @@ -1137,7 +1156,7 @@ static int macsec_drv_create_transmit_sc( rtnl_link_put(link); nl_cache_refill(drv->sk, drv->link_cache); - link = lookup_sc(drv->link_cache, drv->parent_ifi, sci); + link = lookup_sc(drv->link_cache, drv->parent_ifi, sci, cs); if (!link) { wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link"); return -1; diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c index 54964f37..eccaf637 100644 --- a/src/drivers/driver_macsec_qca.c +++ b/src/drivers/driver_macsec_qca.c @@ -861,7 +861,7 @@ static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel) } } - wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__); + wpa_printf(MSG_DEBUG, "%s: no available channel", __func__); return -1; } diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 5d79db65..5892fc1d 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2943,6 +2943,8 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss) wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)", drv->ifindex); + bss->beacon_set = 0; + bss->freq = 0; nl80211_put_wiphy_data_ap(bss); msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON); return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); @@ -4770,10 +4772,24 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) goto fail; - if (drv->device_ap_sme && - (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) && - nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) - goto fail; + if (drv->device_ap_sme) { + u32 flags = 0; + + if (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) { + /* Add the previously used flag attribute to support + * older kernel versions and the newer flag bit for + * newer kernels. */ + if (nla_put_flag(msg, + NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) + goto fail; + flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; + } + + flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT; + + if (nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags)) + goto fail; + } wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x", params->pairwise_ciphers); @@ -5007,15 +5023,19 @@ static int nl80211_put_freq_params(struct nl_msg *msg, if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq)) return -ENOBUFS; + wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled); wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled); wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled); wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled); + wpa_printf(MSG_DEBUG, " * radar_background=%d", + freq->radar_background); 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)) { + if (freq->vht_enabled || + ((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) { enum nl80211_chan_width cw; wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth); @@ -5087,6 +5107,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg, NL80211_CHAN_NO_HT)) return -ENOBUFS; } + if (freq->radar_background) + nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND); + return 0; } @@ -5099,9 +5122,10 @@ static int nl80211_set_channel(struct i802_bss *bss, int ret; wpa_printf(MSG_DEBUG, - "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)", - freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled, - freq->bandwidth, freq->center_freq1, freq->center_freq2); + "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)", + freq->freq, freq->ht_enabled, freq->vht_enabled, + freq->he_enabled, freq->eht_enabled, freq->bandwidth, + freq->center_freq1, freq->center_freq2); msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL : NL80211_CMD_SET_WIPHY); @@ -5250,6 +5274,14 @@ static int wpa_driver_nl80211_sta_add(void *priv, goto fail; } + if (params->eht_capab) { + wpa_hexdump(MSG_DEBUG, " * eht_capab", + params->eht_capab, params->eht_capab_len); + if (nla_put(msg, NL80211_ATTR_EHT_CAPABILITY, + params->eht_capab_len, params->eht_capab)) + goto fail; + } + if (params->ext_capab) { wpa_hexdump(MSG_DEBUG, " * ext_capab", params->ext_capab, params->ext_capab_len); @@ -8300,6 +8332,11 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, if (save_cookie) drv->send_frame_cookie = no_ack ? (u64) -1 : cookie; + if (!wait) { + /* There is no need to store this cookie since there + * is no wait that could be canceled later. */ + goto fail; + } if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) { wpa_printf(MSG_DEBUG, "nl80211: Drop oldest pending send frame cookie 0x%llx", @@ -8430,7 +8467,8 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) u64 cookie; /* Cancel the last pending TX cookie */ - nl80211_frame_wait_cancel(bss, drv->send_frame_cookie); + if (drv->send_frame_cookie != (u64) -1) + nl80211_frame_wait_cancel(bss, drv->send_frame_cookie); /* * Cancel the other pending TX cookies, if any. This is needed since @@ -8622,7 +8660,6 @@ static int wpa_driver_nl80211_deinit_ap(void *priv) if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(bss); - bss->beacon_set = 0; /* * If the P2P GO interface was dynamically added, then it is @@ -8642,7 +8679,6 @@ static int wpa_driver_nl80211_stop_ap(void *priv) if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(bss); - bss->beacon_set = 0; return 0; } @@ -10080,6 +10116,87 @@ error: } +#ifdef CONFIG_IEEE80211AX +static int nl80211_switch_color(void *priv, struct cca_settings *settings) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nlattr *beacon_cca; + struct nl_msg *msg; + int ret = -ENOBUFS; + + wpa_printf(MSG_DEBUG, + "nl80211: Color change request (cca_count=%u color=%d)", + settings->cca_count, settings->cca_color); + + if (drv->nlmode != NL80211_IFTYPE_AP) + return -EOPNOTSUPP; + + if (!settings->beacon_cca.tail) + return -EINVAL; + + if (settings->beacon_cca.tail_len <= settings->counter_offset_beacon || + settings->beacon_cca.tail[settings->counter_offset_beacon] != + settings->cca_count) + return -EINVAL; + + if (settings->beacon_cca.probe_resp && + (settings->beacon_cca.probe_resp_len <= + settings->counter_offset_presp || + settings->beacon_cca.probe_resp[settings->counter_offset_presp] != + settings->cca_count)) + return -EINVAL; + + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_COLOR_CHANGE_REQUEST); + if (!msg || + nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COUNT, + settings->cca_count) || + nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COLOR, + settings->cca_color)) + goto error; + + /* beacon_after params */ + ret = set_beacon_data(msg, &settings->beacon_after); + if (ret) + goto error; + + /* beacon_csa params */ + beacon_cca = nla_nest_start(msg, NL80211_ATTR_COLOR_CHANGE_ELEMS); + if (!beacon_cca) { + ret = -ENOBUFS; + goto error; + } + + ret = set_beacon_data(msg, &settings->beacon_cca); + if (ret) + goto error; + + if (nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_BEACON, + settings->counter_offset_beacon) || + (settings->beacon_cca.probe_resp && + nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_PRESP, + settings->counter_offset_presp))) { + ret = -ENOBUFS; + goto error; + } + + nla_nest_end(msg, beacon_cca); + ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: switch_color failed err=%d (%s)", + ret, strerror(-ret)); + } + return ret; + +error: + nlmsg_free(msg); + wpa_printf(MSG_DEBUG, "nl80211: Could not build color switch request"); + return ret; +} +#endif /* CONFIG_IEEE80211AX */ + + static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr, u8 user_priority, u16 admitted_time) { @@ -11235,6 +11352,8 @@ static int nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv, nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) || (params->vht_enabled && nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) || + (params->eht_enabled && + nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED)) || nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) || add_acs_ch_list(msg, params->freq_list) || @@ -11247,9 +11366,10 @@ static int nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv, nla_nest_end(msg, data); wpa_printf(MSG_DEBUG, - "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d", + "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d", params->hw_mode, params->ht_enabled, params->ht40_enabled, - params->vht_enabled, params->ch_width, params->edmg_enabled); + params->vht_enabled, params->eht_enabled, params->ch_width, + params->edmg_enabled); ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); if (ret) { @@ -12399,6 +12519,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_survey = wpa_driver_nl80211_get_survey, .status = wpa_driver_nl80211_status, .switch_channel = nl80211_switch_channel, +#ifdef CONFIG_IEEE80211AX + .switch_color = nl80211_switch_color, +#endif /* CONFIG_IEEE80211AX */ #ifdef ANDROID_P2P .set_noa = wpa_driver_set_p2p_noa, .get_noa = wpa_driver_get_p2p_noa, diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 400eb4be..75df36c8 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -664,6 +664,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION)) capa->flags2 |= WPA_DRIVER_FLAGS2_OCV; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_RADAR_BACKGROUND)) + capa->flags2 |= WPA_DRIVER_RADAR_BACKGROUND; } @@ -919,8 +923,15 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT], tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]); - if (tb[NL80211_ATTR_DEVICE_AP_SME]) + if (tb[NL80211_ATTR_DEVICE_AP_SME]) { + u32 ap_sme_features_flags = + nla_get_u32(tb[NL80211_ATTR_DEVICE_AP_SME]); + + if (ap_sme_features_flags & NL80211_AP_SME_SA_QUERY_OFFLOAD) + capa->flags2 |= WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP; + info->device_ap_sme = 1; + } wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]); wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]); @@ -1335,7 +1346,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->has_capability = 1; drv->has_driver_key_mgmt = info.has_key_mgmt | info.has_key_mgmt_iftype; - /* Fallback to hardcoded defaults if the driver does nott advertize any + /* Fallback to hardcoded defaults if the driver does not advertise any * AKM capabilities. */ if (!drv->has_driver_key_mgmt) { drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | @@ -1772,12 +1783,14 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb) } -static void phy_info_iftype_copy(struct he_capabilities *he_capab, +static void phy_info_iftype_copy(struct hostapd_hw_modes *mode, enum ieee80211_op_mode opmode, struct nlattr **tb, struct nlattr **tb_flags) { enum nl80211_iftype iftype; size_t len; + struct he_capabilities *he_capab = &mode->he_capab[opmode]; + struct eht_capabilities *eht_capab = &mode->eht_capab[opmode]; switch (opmode) { case IEEE80211_MODE_INFRA: @@ -1847,6 +1860,47 @@ static void phy_info_iftype_copy(struct he_capabilities *he_capab, capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]); he_capab->he_6ghz_capa = le_to_host16(capa); } + + if (!tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] || + !tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) + return; + + eht_capab->eht_supported = true; + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] && + nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]) >= 2) { + const u8 *pos; + + pos = nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]); + eht_capab->mac_cap = WPA_GET_LE16(pos); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]); + if (len > sizeof(eht_capab->phy_cap)) + len = sizeof(eht_capab->phy_cap); + os_memcpy(eht_capab->phy_cap, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]); + if (len > sizeof(eht_capab->mcs)) + len = sizeof(eht_capab->mcs); + os_memcpy(eht_capab->mcs, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]); + if (len > sizeof(eht_capab->ppet)) + len = sizeof(eht_capab->ppet); + os_memcpy(&eht_capab->ppet, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]), + len); + } } @@ -1868,7 +1922,7 @@ static int phy_info_iftype(struct hostapd_hw_modes *mode, return NL_STOP; for (i = 0; i < IEEE80211_MODE_NUM; i++) - phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags); + phy_info_iftype_copy(mode, i, tb, tb_flags); return NL_OK; } @@ -2430,7 +2484,7 @@ static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes, for (i = 0; i < num_modes; i++) { struct hostapd_hw_modes *mode = &modes[i]; - char str[200]; + char str[1000]; char *pos = str; char *end = pos + sizeof(str); int j, res; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 2926a456..5c103a41 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -171,6 +171,13 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_UNPROT_BEACON) C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS) C2S(NL80211_CMD_SET_SAR_SPECS) + C2S(NL80211_CMD_OBSS_COLOR_COLLISION) + C2S(NL80211_CMD_COLOR_CHANGE_REQUEST) + C2S(NL80211_CMD_COLOR_CHANGE_STARTED) + C2S(NL80211_CMD_COLOR_CHANGE_ABORTED) + C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED) + C2S(NL80211_CMD_SET_FILS_AAD) + C2S(NL80211_CMD_ASSOC_COMEBACK) C2S(__NL80211_CMD_AFTER_LAST) } #undef C2S @@ -2822,7 +2829,8 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, nla_len(tb[NL80211_ATTR_FRAME])); break; default: - wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from " + wpa_printf(MSG_INFO, + "nl80211: Unexpected ethertype 0x%04x from " MACSTR " over control port", ethertype, MAC2STR(src_addr)); break; @@ -2871,9 +2879,12 @@ static void nl80211_frame_wait_cancel(struct wpa_driver_nl80211_data *drv, } } wpa_printf(MSG_DEBUG, - "nl80211: TX frame wait expired for cookie 0x%llx%s", + "nl80211: TX frame wait expired for cookie 0x%llx%s%s", (long long unsigned int) cookie, - match ? " (match)" : ""); + match ? " (match)" : "", + drv->send_frame_cookie == cookie ? " (match-saved)" : ""); + if (drv->send_frame_cookie == cookie) + drv->send_frame_cookie = (u64) -1; if (!match) return; @@ -2887,6 +2898,69 @@ static void nl80211_frame_wait_cancel(struct wpa_driver_nl80211_data *drv, } +static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv, + struct nlattr *mac, struct nlattr *timeout) +{ + if (!mac || !timeout) + return; + wpa_printf(MSG_DEBUG, "nl80211: Association comeback requested by " + MACSTR " (timeout: %u ms)", + MAC2STR((u8 *) nla_data(mac)), nla_get_u32(timeout)); +} + + +#ifdef CONFIG_IEEE80211AX + +static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + union wpa_event_data data; + + if (!tb[NL80211_ATTR_OBSS_COLOR_BITMAP]) + return; + + os_memset(&data, 0, sizeof(data)); + data.bss_color_collision.bitmap = + nla_get_u64(tb[NL80211_ATTR_OBSS_COLOR_BITMAP]); + + wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08lx", + data.bss_color_collision.bitmap); + wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data); +} + + +static void +nl80211_color_change_announcement_started(struct wpa_driver_nl80211_data *drv) +{ + union wpa_event_data data = {}; + + wpa_printf(MSG_DEBUG, "nl80211: CCA started"); + wpa_supplicant_event(drv->ctx, EVENT_CCA_STARTED_NOTIFY, &data); +} + + +static void +nl80211_color_change_announcement_aborted(struct wpa_driver_nl80211_data *drv) +{ + union wpa_event_data data = {}; + + wpa_printf(MSG_DEBUG, "nl80211: CCA aborted"); + wpa_supplicant_event(drv->ctx, EVENT_CCA_ABORTED_NOTIFY, &data); +} + + +static void +nl80211_color_change_announcement_completed(struct wpa_driver_nl80211_data *drv) +{ + union wpa_event_data data = {}; + + wpa_printf(MSG_DEBUG, "nl80211: CCA completed"); + wpa_supplicant_event(drv->ctx, EVENT_CCA_NOTIFY, &data); +} + +#endif /* CONFIG_IEEE80211AX */ + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -3136,6 +3210,24 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_FRAME_WAIT_CANCEL: nl80211_frame_wait_cancel(drv, tb[NL80211_ATTR_COOKIE]); break; + case NL80211_CMD_ASSOC_COMEBACK: + nl80211_assoc_comeback(drv, tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_TIMEOUT]); + break; +#ifdef CONFIG_IEEE80211AX + case NL80211_CMD_OBSS_COLOR_COLLISION: + nl80211_obss_color_collision(drv, tb); + break; + case NL80211_CMD_COLOR_CHANGE_STARTED: + nl80211_color_change_announcement_started(drv); + break; + case NL80211_CMD_COLOR_CHANGE_ABORTED: + nl80211_color_change_announcement_aborted(drv); + break; + case NL80211_CMD_COLOR_CHANGE_COMPLETED: + nl80211_color_change_announcement_completed(drv); + break; +#endif /* CONFIG_IEEE80211AX */ default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 13160848..b82e5af2 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -713,6 +713,7 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, + [NL80211_BSS_BEACON_TSF] = { .type = NLA_U64 }, [NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 }, [NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC }, [NL80211_BSS_LAST_SEEN_BOOTTIME] = { .type = NLA_U64 }, @@ -774,8 +775,10 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); if (bss[NL80211_BSS_BEACON_TSF]) { u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]); - if (tsf > r->tsf) + if (tsf > r->tsf) { r->tsf = tsf; + r->beacon_newer = true; + } } if (bss[NL80211_BSS_SEEN_MS_AGO]) r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); diff --git a/src/drivers/ndis_events.c b/src/drivers/ndis_events.c index 93673a36..4d4ec81d 100644 --- a/src/drivers/ndis_events.c +++ b/src/drivers/ndis_events.c @@ -372,8 +372,9 @@ ndis_events_indicate(IWbemObjectSink *this, long lObjectCount, L"MSNdis_NotifyAdapterRemoval") == 0) { ndis_events_adapter_removal(events); } else { - wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: " - "'%S'", vtClass.bstrVal); + wpa_printf(MSG_DEBUG, + "Unexpected event - __CLASS: '%S'", + vtClass.bstrVal); } VariantClear(&vtClass); diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index f962c06e..0568a790 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -11,7 +11,7 @@ * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -300,6 +300,29 @@ * the interface goes down. */ +/** + * DOC: FILS shared key crypto offload + * + * This feature is applicable to drivers running in AP mode. + * + * FILS shared key crypto offload can be advertised by drivers by setting + * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD flag. The drivers that support + * FILS shared key crypto offload should be able to encrypt and decrypt + * association frames for FILS shared key authentication as per IEEE 802.11ai. + * With this capability, for FILS key derivation, drivers depend on userspace. + * + * After FILS key derivation, userspace shares the FILS AAD details with the + * driver and the driver stores the same to use in decryption of association + * request and in encryption of association response. The below parameters + * should be given to the driver in %NL80211_CMD_SET_FILS_AAD. + * %NL80211_ATTR_MAC - STA MAC address, used for storing FILS AAD per STA + * %NL80211_ATTR_FILS_KEK - Used for encryption or decryption + * %NL80211_ATTR_FILS_NONCES - Used for encryption or decryption + * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) + * + * Once the association is done, the driver cleans the FILS AAD data. + */ + /** * enum nl80211_commands - supported nl80211 commands * @@ -337,7 +360,10 @@ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from * userspace to request deletion of a virtual interface, then requires - * attribute %NL80211_ATTR_IFINDEX. + * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are + * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, + * and if this command is used for the transmitting interface, then all + * the non-transmitting interfaces are deleted as well. * * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. @@ -1185,6 +1211,32 @@ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to * specify the wiphy index to be applied to. * + * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever + * mac80211/drv detects a bss color collision. + * + * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that + * userspace wants to change the BSS color. + * + * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has + * started + * + * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has + * been aborted + * + * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change + * has completed + * + * @NL80211_CMD_SET_FILS_AAD: Set FILS AAD data to the driver using - + * &NL80211_ATTR_MAC - for STA MAC address + * &NL80211_ATTR_FILS_KEK - for KEK + * &NL80211_ATTR_FILS_NONCES - for FILS Nonces + * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) + * + * @NL80211_CMD_ASSOC_COMEBACK: notification about an association + * temporal rejection with comeback. The event includes %NL80211_ATTR_MAC + * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to + * specify the timeout value. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1417,6 +1469,18 @@ enum nl80211_commands { NL80211_CMD_SET_SAR_SPECS, + NL80211_CMD_OBSS_COLOR_COLLISION, + + NL80211_CMD_COLOR_CHANGE_REQUEST, + + NL80211_CMD_COLOR_CHANGE_STARTED, + NL80211_CMD_COLOR_CHANGE_ABORTED, + NL80211_CMD_COLOR_CHANGE_COMPLETED, + + NL80211_CMD_SET_FILS_AAD, + + NL80211_CMD_ASSOC_COMEBACK, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2413,7 +2477,9 @@ enum nl80211_commands { * space supports external authentication. This attribute shall be used * with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver * may offload authentication processing to user space if this capability - * is indicated in the respective requests from the user space. + * is indicated in the respective requests from the user space. (This flag + * attribute deprecated for %NL80211_CMD_START_AP, use + * %NL80211_ATTR_AP_SETTINGS_FLAGS) * * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. @@ -2560,6 +2626,43 @@ enum nl80211_commands { * disassoc events to indicate that an immediate reconnect to the AP * is desired. * + * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the + * %NL80211_CMD_OBSS_COLOR_COLLISION event. + * + * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's + * until the color switch event. + * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are + * switching to + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. + * + * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID + * advertisements (MBSSID) parameters in AP mode. + * Kernel uses this attribute to indicate the driver's support for MBSSID + * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. + * Userspace should use this attribute to configure per interface MBSSID + * parameters. + * See &enum nl80211_mbssid_config_attributes for details. + * + * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * + * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain + * available for radar/CAC detection on some hw. This chain can't be used + * to transmit or receive frames and it is bounded to a running wdev. + * Background radar/CAC detection allows to avoid the CAC downtime + * switching on a different channel during CAC detection on the selected + * radar channel. + * + * @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags, + * enumerated in &enum nl80211_ap_settings_flags. This attribute shall be + * used with %NL80211_CMD_START_AP request. + * + * @NL80211_ATTR_EHT_CAPABILITY: EHT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION). Can be set + * only if %NL80211_STA_FLAG_WME is set. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3057,6 +3160,21 @@ enum nl80211_attrs { NL80211_ATTR_DISABLE_HE, + NL80211_ATTR_OBSS_COLOR_BITMAP, + + NL80211_ATTR_COLOR_CHANGE_COUNT, + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + + NL80211_ATTR_RADAR_BACKGROUND, + + NL80211_ATTR_AP_SETTINGS_FLAGS, + + NL80211_ATTR_EHT_CAPABILITY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3112,6 +3230,8 @@ enum nl80211_attrs { #define NL80211_HE_MAX_CAPABILITY_LEN 54 #define NL80211_MAX_NR_CIPHER_SUITES 5 #define NL80211_MAX_NR_AKM_SUITES 2 +#define NL80211_EHT_MIN_CAPABILITY_LEN 13 +#define NL80211_EHT_MAX_CAPABILITY_LEN 51 #define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 @@ -3139,7 +3259,7 @@ enum nl80211_attrs { * and therefore can't be created in the normal ways, use the * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE * commands to create and destroy one - * @NL80211_IF_TYPE_OCB: Outside Context of a BSS + * @NL80211_IFTYPE_OCB: Outside Context of a BSS * This mode corresponds to the MIB variable dot11OCBActivated=true * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) * @NL80211_IFTYPE_MAX: highest interface type number currently defined @@ -3280,6 +3400,56 @@ enum nl80211_he_ru_alloc { NL80211_RATE_INFO_HE_RU_ALLOC_2x996, }; +/** + * enum nl80211_eht_gi - EHT guard interval + * @NL80211_RATE_INFO_EHT_GI_0_8: 0.8 usec + * @NL80211_RATE_INFO_EHT_GI_1_6: 1.6 usec + * @NL80211_RATE_INFO_EHT_GI_3_2: 3.2 usec + */ +enum nl80211_eht_gi { + NL80211_RATE_INFO_EHT_GI_0_8, + NL80211_RATE_INFO_EHT_GI_1_6, + NL80211_RATE_INFO_EHT_GI_3_2, +}; + +/** + * enum nl80211_eht_ru_alloc - EHT RU allocation values + * @NL80211_RATE_INFO_EHT_RU_ALLOC_26: 26-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_52: 52-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: 52+26-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_106: 106-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: 106+26 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_242: 242-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_484: 484-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: 484+242 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996: 996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: 996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: 996+484+242 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996: 2x996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484: 2x996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996: 3x996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484: 3x996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_4x996: 4x996-tone RU allocation + */ +enum nl80211_eht_ru_alloc { + NL80211_RATE_INFO_EHT_RU_ALLOC_26, + NL80211_RATE_INFO_EHT_RU_ALLOC_52, + NL80211_RATE_INFO_EHT_RU_ALLOC_52P26, + NL80211_RATE_INFO_EHT_RU_ALLOC_106, + NL80211_RATE_INFO_EHT_RU_ALLOC_106P26, + NL80211_RATE_INFO_EHT_RU_ALLOC_242, + NL80211_RATE_INFO_EHT_RU_ALLOC_484, + NL80211_RATE_INFO_EHT_RU_ALLOC_484P242, + NL80211_RATE_INFO_EHT_RU_ALLOC_996, + NL80211_RATE_INFO_EHT_RU_ALLOC_996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242, + NL80211_RATE_INFO_EHT_RU_ALLOC_2x996, + NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_3x996, + NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_4x996, +}; + /** * enum nl80211_rate_info - bitrate information * @@ -3319,6 +3489,13 @@ enum nl80211_he_ru_alloc { * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1) * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then * non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc) + * @NL80211_RATE_INFO_320_MHZ_WIDTH: 320 MHz bitrate + * @NL80211_RATE_INFO_EHT_MCS: EHT MCS index (u8, 0-15) + * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8) + * @NL80211_RATE_INFO_EHT_GI: EHT guard interval identifier + * (u8, see &enum nl80211_eht_gi) + * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then + * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc) * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -3340,6 +3517,11 @@ enum nl80211_rate_info { NL80211_RATE_INFO_HE_GI, NL80211_RATE_INFO_HE_DCM, NL80211_RATE_INFO_HE_RU_ALLOC, + NL80211_RATE_INFO_320_MHZ_WIDTH, + NL80211_RATE_INFO_EHT_MCS, + NL80211_RATE_INFO_EHT_NSS, + NL80211_RATE_INFO_EHT_GI, + NL80211_RATE_INFO_EHT_RU_ALLOC, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -3650,11 +3832,20 @@ enum nl80211_mpath_info { * capabilities IE * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as * defined in HE capabilities IE - * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently - * defined * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16), * given for all 6 GHz band channels + * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are + * advertised on this band/for this iftype (binary) + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: EHT MAC capabilities as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: EHT PHY capabilities as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: EHT supported NSS/MCS as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as + * defined in EHT capabilities element * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use + * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined */ enum nl80211_band_iftype_attr { __NL80211_BAND_IFTYPE_ATTR_INVALID, @@ -3665,6 +3856,11 @@ enum nl80211_band_iftype_attr { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, + NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE, /* keep last */ __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, @@ -3809,6 +4005,10 @@ enum nl80211_wmm_rule { * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_320MHZ: any 320 MHz channel using this channel + * as the primary or any of the secondary channels isn't possible + * @NL80211_FREQUENCY_ATTR_NO_EHT: EHT operation is not allowed on this channel + * in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -3845,6 +4045,8 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_4MHZ, NL80211_FREQUENCY_ATTR_8MHZ, NL80211_FREQUENCY_ATTR_16MHZ, + NL80211_FREQUENCY_ATTR_NO_320MHZ, + NL80211_FREQUENCY_ATTR_NO_EHT, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -4043,6 +4245,7 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed * @NL80211_RRF_NO_HE: HE operation not allowed + * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -4061,6 +4264,7 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_80MHZ = 1<<15, NL80211_RRF_NO_160MHZ = 1<<16, NL80211_RRF_NO_HE = 1<<17, + NL80211_RRF_NO_320MHZ = 1<<18, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR @@ -4558,6 +4762,8 @@ enum nl80211_key_mode { * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel + * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * attribute must be provided as well */ enum nl80211_chan_width { NL80211_CHAN_WIDTH_20_NOHT, @@ -4573,6 +4779,7 @@ enum nl80211_chan_width { NL80211_CHAN_WIDTH_4, NL80211_CHAN_WIDTH_8, NL80211_CHAN_WIDTH_16, + NL80211_CHAN_WIDTH_320, }; /** @@ -4887,6 +5094,7 @@ enum nl80211_txrate_gi { * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz) * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz) * @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs + * @NL80211_BAND_LC: light communication band (placeholder) * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace * since newer kernel versions may support more bands */ @@ -4896,6 +5104,7 @@ enum nl80211_band { NL80211_BAND_60GHZ, NL80211_BAND_6GHZ, NL80211_BAND_S1GHZ, + NL80211_BAND_LC, NUM_NL80211_BANDS, }; @@ -5462,7 +5671,7 @@ enum nl80211_iface_limit_attrs { * => allows 8 of AP/GO that can have BI gcd >= min gcd * * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 - * => allows two STAs on different channels + * => allows two STAs on the same or on different channels * * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 * => allows a STA plus three P2P interfaces @@ -5507,7 +5716,7 @@ enum nl80211_if_combination_attrs { * @NL80211_PLINK_ESTAB: mesh peer link is established * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh - * plink are discarded + * plink are discarded, except for authentication frames * @NUM_NL80211_PLINK_STATES: number of peer link states * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states */ @@ -5644,13 +5853,15 @@ enum nl80211_tdls_operation { NL80211_TDLS_DISABLE_LINK, }; -/* +/** * enum nl80211_ap_sme_features - device-integrated AP features - * Reserved for future use, no bits are defined in - * NL80211_ATTR_DEVICE_AP_SME yet. -enum nl80211_ap_sme_features { -}; + * @NL80211_AP_SME_SA_QUERY_OFFLOAD: SA Query procedures offloaded to driver + * when user space indicates support for SA Query procedures offload during + * "start ap" with %NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT. */ +enum nl80211_ap_sme_features { + NL80211_AP_SME_SA_QUERY_OFFLOAD = 1 << 0, +}; /** * enum nl80211_feature_flags - device/driver features @@ -5950,6 +6161,17 @@ enum nl80211_feature_flags { * frame protection for all management frames exchanged during the * negotiation and range measurement procedure. * + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * + * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports + * FILS encryption and decryption for (Re)Association Request and Response + * frames. Userspace has to share FILS AAD details to the driver by using + * @NL80211_CMD_SET_FILS_AAD. + * + * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC + * detection. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -6014,6 +6236,9 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_SECURE_LTF, NL80211_EXT_FEATURE_SECURE_RTT, NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, + NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD, + NL80211_EXT_FEATURE_RADAR_BACKGROUND, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -6912,6 +7137,9 @@ enum nl80211_peer_measurement_ftm_capa { * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set. + * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the + * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED + * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set. * * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number @@ -6931,6 +7159,7 @@ enum nl80211_peer_measurement_ftm_req { NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, + NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, /* keep last */ NUM_NL80211_PMSR_FTM_REQ_ATTR, @@ -7299,4 +7528,76 @@ enum nl80211_sar_specs_attrs { NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, }; +/** + * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced + * multi-BSSID advertisements (EMA) in AP mode. + * Kernel uses some of these attributes to advertise driver's support for + * MBSSID and EMA. + * Remaining attributes should be used by the userspace to configure the + * features. + * + * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid + * + * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise + * the maximum number of MBSSID interfaces supported by the driver. + * Driver should indicate MBSSID support by setting + * wiphy->mbssid_max_interfaces to a value more than or equal to 2. + * + * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel + * to advertise the maximum profile periodicity supported by the driver + * if EMA is enabled. Driver should indicate EMA support to the userspace + * by setting wiphy->ema_max_profile_periodicity to + * a non-zero value. + * + * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of + * this BSS (u8) in the multiple BSSID set. + * Value must be set to 0 for the transmitting interface and non-zero for + * all non-transmitting interfaces. The userspace will be responsible + * for using unique indices for the interfaces. + * Range: 0 to wiphy->mbssid_max_interfaces-1. + * + * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for + * a non-transmitted profile which provides the interface index (u32) of + * the transmitted profile. The value must match one of the interface + * indices advertised by the kernel. Optional if the interface being set up + * is the transmitting one, however, if provided then the value must match + * the interface index of the same. + * + * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. + * Setting this flag is permitted only if the driver advertises EMA support + * by setting wiphy->ema_max_profile_periodicity to non-zero. + * + * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal + * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute + */ +enum nl80211_mbssid_config_attributes { + __NL80211_MBSSID_CONFIG_ATTR_INVALID, + + NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, + NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, + NL80211_MBSSID_CONFIG_ATTR_INDEX, + NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, + NL80211_MBSSID_CONFIG_ATTR_EMA, + + /* keep last */ + __NL80211_MBSSID_CONFIG_ATTR_LAST, + NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, +}; + +/** + * enum nl80211_ap_settings_flags - AP settings flags + * + * @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external + * authentication. + * @NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT: Userspace supports SA Query + * procedures offload to driver. If driver advertises + * %NL80211_AP_SME_SA_QUERY_OFFLOAD in AP SME features, userspace shall + * ignore SA Query procedures and validations when this flag is set by + * userspace. + */ +enum nl80211_ap_settings_flags { + NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0, + NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h index 70999c4e..3346ec53 100644 --- a/src/eap_common/eap_defs.h +++ b/src/eap_common/eap_defs.h @@ -72,7 +72,7 @@ enum eap_type { EAP_TYPE_MD5 = 4, /* RFC 3748 */ EAP_TYPE_OTP = 5 /* RFC 3748 */, EAP_TYPE_GTC = 6, /* RFC 3748 */ - EAP_TYPE_TLS = 13 /* RFC 2716 */, + EAP_TYPE_TLS = 13 /* RFC 5216 */, EAP_TYPE_LEAP = 17 /* Cisco proprietary */, EAP_TYPE_SIM = 18 /* RFC 4186 */, EAP_TYPE_TTLS = 21 /* RFC 5281 */, diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 5fd370f7..276dca31 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1684,6 +1684,7 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) struct wpabuf *resp; const u8 *identity; size_t identity_len; + struct wpabuf *privacy_identity = NULL; if (config == NULL) { wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration " @@ -1706,6 +1707,30 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) identity_len = config->machine_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity", identity, identity_len); + } else if (config->imsi_privacy_key && config->identity && + config->identity_len > 0) { + const u8 *pos = config->identity; + const u8 *end = config->identity + config->identity_len; + + privacy_identity = wpabuf_alloc(9 + config->identity_len); + if (!privacy_identity) + return NULL; + + /* Include method prefix */ + if (*pos == '0' || *pos == '1' || *pos == '6') + wpabuf_put_u8(privacy_identity, *pos); + wpabuf_put_str(privacy_identity, "anonymous"); + + /* Include realm */ + while (pos < end && *pos != '@') + pos++; + wpabuf_put_data(privacy_identity, pos, end - pos); + + identity = wpabuf_head(privacy_identity); + identity_len = wpabuf_len(privacy_identity); + wpa_hexdump_ascii(MSG_DEBUG, + "EAP: using IMSI privacy anonymous identity", + identity, identity_len); } else { identity = config->identity; identity_len = config->identity_len; @@ -1742,6 +1767,7 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) return NULL; wpabuf_put_data(resp, identity, identity_len); + wpabuf_free(privacy_identity); return resp; } @@ -2157,6 +2183,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, eap_notify_status(sm, "remote TLS alert", data->alert.description); break; + case TLS_UNSAFE_RENEGOTIATION_DISABLED: + wpa_printf(MSG_INFO, + "TLS handshake failed due to the server not supporting safe renegotiation (RFC 5746); phase1 parameter allow_unsafe_renegotiation=1 can be used to work around this"); + eap_notify_status(sm, "unsafe server renegotiation", "failure"); + break; } os_free(hash_hex); diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index 8c475f13..8caae1d6 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -9,6 +9,7 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" #include "pcsc_funcs.h" #include "crypto/crypto.h" #include "crypto/sha1.h" @@ -58,6 +59,7 @@ struct eap_aka_data { u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX]; size_t last_kdf_count; int error_code; + struct crypto_rsa_key *imsi_privacy_key; }; @@ -101,6 +103,25 @@ static void * eap_aka_init(struct eap_sm *sm) data->eap_method = EAP_TYPE_AKA; + if (config && config->imsi_privacy_key) { +#ifdef CRYPTO_RSA_OAEP_SHA256 + data->imsi_privacy_key = crypto_rsa_key_read( + config->imsi_privacy_key, false); + if (!data->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "EAP-AKA: Failed to read/parse IMSI privacy key %s", + config->imsi_privacy_key); + os_free(data); + return NULL; + } +#else /* CRYPTO_RSA_OAEP_SHA256 */ + wpa_printf(MSG_ERROR, + "EAP-AKA: No support for imsi_privacy_key in the build"); + os_free(data); + return NULL; +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + } + /* Zero is a valid error code, so we need to initialize */ data->error_code = NO_EAP_METHOD_ERROR; @@ -160,6 +181,9 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv) wpabuf_free(data->id_msgs); os_free(data->network_name); eap_aka_clear_keys(data, 0); +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(data->imsi_privacy_key); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ os_free(data); } } @@ -617,6 +641,47 @@ static struct wpabuf * eap_aka_synchronization_failure( } +#ifdef CRYPTO_RSA_OAEP_SHA256 +static struct wpabuf * +eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key, + const u8 *identity, size_t identity_len) +{ + struct wpabuf *imsi_buf, *enc; + char *b64; + size_t b64_len; + + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity", + identity, identity_len); + + imsi_buf = wpabuf_alloc_copy(identity, identity_len); + if (!imsi_buf) + return NULL; + enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf); + wpabuf_free(imsi_buf); + if (!enc) + return NULL; + + b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len); + wpabuf_free(enc); + if (!b64) + return NULL; + + enc = wpabuf_alloc(1 + b64_len); + if (!enc) { + os_free(b64); + return NULL; + } + wpabuf_put_u8(enc, '\0'); + wpabuf_put_data(enc, b64, b64_len); + os_free(b64); + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity", + wpabuf_head(enc), wpabuf_len(enc)); + + return enc; +} +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + + static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, struct eap_aka_data *data, u8 id, @@ -625,6 +690,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, const u8 *identity = NULL; size_t identity_len = 0; struct eap_sim_msg *msg; + struct wpabuf *enc_identity = NULL; data->reauth = 0; if (id_req == ANY_ID && data->reauth_id) { @@ -649,6 +715,22 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, ids &= ~CLEAR_PSEUDONYM; eap_aka_clear_identities(sm, data, ids); } +#ifdef CRYPTO_RSA_OAEP_SHA256 + if (identity && data->imsi_privacy_key) { + enc_identity = eap_aka_encrypt_identity( + data->imsi_privacy_key, + identity, identity_len); + if (!enc_identity) { + wpa_printf(MSG_INFO, + "EAP-AKA: Failed to encrypt permanent identity"); + return eap_aka_client_error( + data, id, + EAP_AKA_UNABLE_TO_PROCESS_PACKET); + } + identity = wpabuf_head(enc_identity); + identity_len = wpabuf_len(enc_identity); + } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } if (id_req != NO_ID_REQ) eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); @@ -663,6 +745,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, identity, identity_len); } + wpabuf_free(enc_identity); return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index 3238f74f..eaf514b1 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -103,24 +103,6 @@ struct eap_peer_cert_config { */ char *private_key_passwd; - /** - * dh_file - File path to DH/DSA parameters file (in PEM format) - * - * This is an optional configuration file for setting parameters for an - * ephemeral DH key exchange. In most cases, the default RSA - * authentication does not use this configuration. However, it is - * possible setup RSA to use ephemeral DH key exchange. In addition, - * ciphers with DSA keys always use ephemeral DH keys. This can be used - * to achieve forward secrecy. If the file is in DSA parameters format, - * it will be automatically converted into DH params. 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. - */ - char *dh_file; - /** * subject_match - Constraint for server certificate subject * @@ -335,6 +317,16 @@ struct eap_peer_config { u8 *imsi_identity; size_t imsi_identity_len; + /** + * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate) + * + * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent + * identity (IMSI) to improve privacy. The X.509v3 certificate needs to + * include a 2048-bit RSA public key and this is from the operator who + * authenticates the SIM/USIM. + */ + char *imsi_privacy_key; + /** * machine_identity - EAP Identity for machine credential * diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index 09866277..3b4c836d 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -9,7 +9,9 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" #include "pcsc_funcs.h" +#include "crypto/crypto.h" #include "crypto/milenage.h" #include "crypto/random.h" #include "eap_peer/eap_i.h" @@ -49,6 +51,7 @@ struct eap_sim_data { int result_ind, use_result_ind; int use_pseudonym; int error_code; + struct crypto_rsa_key *imsi_privacy_key; }; @@ -98,6 +101,25 @@ static void * eap_sim_init(struct eap_sm *sm) return NULL; } + if (config && config->imsi_privacy_key) { +#ifdef CRYPTO_RSA_OAEP_SHA256 + data->imsi_privacy_key = crypto_rsa_key_read( + config->imsi_privacy_key, false); + if (!data->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "EAP-SIM: Failed to read/parse IMSI privacy key %s", + config->imsi_privacy_key); + os_free(data); + return NULL; + } +#else /* CRYPTO_RSA_OAEP_SHA256 */ + wpa_printf(MSG_ERROR, + "EAP-SIM: No support for imsi_privacy_key in the build"); + os_free(data); + return NULL; +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + } + /* Zero is a valid error code, so we need to initialize */ data->error_code = NO_EAP_METHOD_ERROR; @@ -162,6 +184,9 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv) os_free(data->reauth_id); os_free(data->last_eap_identity); eap_sim_clear_keys(data, 0); +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(data->imsi_privacy_key); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ os_free(data); } } @@ -481,6 +506,47 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id, } +#ifdef CRYPTO_RSA_OAEP_SHA256 +static struct wpabuf * +eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key, + const u8 *identity, size_t identity_len) +{ + struct wpabuf *imsi_buf, *enc; + char *b64; + size_t b64_len; + + wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity", + identity, identity_len); + + imsi_buf = wpabuf_alloc_copy(identity, identity_len); + if (!imsi_buf) + return NULL; + enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf); + wpabuf_free(imsi_buf); + if (!enc) + return NULL; + + b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len); + wpabuf_free(enc); + if (!b64) + return NULL; + + enc = wpabuf_alloc(1 + b64_len); + if (!enc) { + os_free(b64); + return NULL; + } + wpabuf_put_u8(enc, '\0'); + wpabuf_put_data(enc, b64, b64_len); + os_free(b64); + wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity", + wpabuf_head(enc), wpabuf_len(enc)); + + return enc; +} +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + + static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, struct eap_sim_data *data, u8 id, enum eap_sim_id_req id_req) @@ -489,6 +555,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, size_t identity_len = 0; struct eap_sim_msg *msg; struct wpabuf *resp; + struct wpabuf *enc_identity = NULL; data->reauth = 0; if (id_req == ANY_ID && data->reauth_id) { @@ -513,6 +580,22 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, ids &= ~CLEAR_PSEUDONYM; eap_sim_clear_identities(sm, data, ids); } +#ifdef CRYPTO_RSA_OAEP_SHA256 + if (identity && data->imsi_privacy_key) { + enc_identity = eap_sim_encrypt_identity( + data->imsi_privacy_key, + identity, identity_len); + if (!enc_identity) { + wpa_printf(MSG_INFO, + "EAP-SIM: Failed to encrypt permanent identity"); + return eap_sim_client_error( + data, id, + EAP_SIM_UNABLE_TO_PROCESS_PACKET); + } + identity = wpabuf_head(enc_identity); + identity_len = wpabuf_len(enc_identity); + } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } if (id_req != NO_ID_REQ) eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); @@ -526,6 +609,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, identity, identity_len); } + wpabuf_free(enc_identity); if (!data->reauth) { wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT", data->nonce_mt, EAP_SIM_NONCE_MT_LEN); diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c index 0d479f1c..4167e992 100644 --- a/src/eap_peer/eap_tls.c +++ b/src/eap_peer/eap_tls.c @@ -1,5 +1,5 @@ /* - * EAP peer method: EAP-TLS (RFC 2716) + * EAP peer method: EAP-TLS (RFC 5216, RFC 9190) * Copyright (c) 2004-2008, 2012-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. @@ -26,6 +26,7 @@ struct eap_tls_data { void *ssl_ctx; u8 eap_type; struct wpabuf *pending_resp; + bool prot_success_received; }; @@ -302,15 +303,20 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, return NULL; } - /* draft-ietf-emu-eap-tls13-13 Section 2.5 */ + /* RFC 9190 Section 2.5 */ if (res == 2 && data->ssl.tls_v13 && wpabuf_len(resp) == 1 && *wpabuf_head_u8(resp) == 0) { - wpa_printf(MSG_DEBUG, "EAP-TLS: ACKing Commitment Message"); + wpa_printf(MSG_DEBUG, + "EAP-TLS: ACKing protected success indication (appl data 0x00)"); eap_peer_tls_reset_output(&data->ssl); res = 1; + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + data->prot_success_received = true; } - if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) + if (tls_connection_established(data->ssl_ctx, data->ssl.conn) && + (!data->ssl.tls_v13 || data->prot_success_received)) eap_tls_success(sm, data, ret); if (res == 1) { @@ -335,6 +341,7 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) wpabuf_free(data->pending_resp); data->pending_resp = NULL; + data->prot_success_received = false; } diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 1aaca360..3050456d 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -102,6 +102,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params, params->flags |= TLS_CONN_SUITEB_NO_ECDH; if (os_strstr(txt, "tls_suiteb_no_ecdh=0")) params->flags &= ~TLS_CONN_SUITEB_NO_ECDH; + if (os_strstr(txt, "allow_unsafe_renegotiation=1")) + params->flags |= TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION; + if (os_strstr(txt, "allow_unsafe_renegotiation=0")) + params->flags &= ~TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION; } @@ -113,7 +117,6 @@ static void eap_tls_cert_params_from_conf(struct tls_connection_params *params, params->client_cert = config->client_cert; params->private_key = config->private_key; params->private_key_passwd = config->private_key_passwd; - params->dh_file = config->dh_file; params->subject_match = config->subject_match; params->altsubject_match = config->altsubject_match; params->check_cert_subject = config->check_cert_subject; @@ -192,18 +195,20 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, * TLS v1.3 changes, so disable this by default for now. */ params->flags |= TLS_CONN_DISABLE_TLSv1_3; } +#ifndef EAP_TLSV1_3 if (data->eap_type == EAP_TYPE_TLS || data->eap_type == EAP_UNAUTH_TLS_TYPE || data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) { /* While the current EAP-TLS implementation is more or less - * complete for TLS v1.3, there has been no interoperability - * testing with other implementations, so disable for by default - * for now until there has been chance to confirm that no - * significant interoperability issues show up with TLS version - * update. + * complete for TLS v1.3, there has been only minimal + * interoperability testing with other implementations, so + * disable it by default for now until there has been chance to + * confirm that no significant interoperability issues show up + * with TLS version update. */ params->flags |= TLS_CONN_DISABLE_TLSv1_3; } +#endif /* EAP_TLSV1_3 */ if (phase2 && sm->use_machine_cred) { wpa_printf(MSG_DEBUG, "TLS: using machine config options"); eap_tls_params_from_conf2m(params, config); @@ -228,9 +233,7 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, ¶ms->client_cert_blob_len) || eap_tls_check_blob(sm, ¶ms->private_key, ¶ms->private_key_blob, - ¶ms->private_key_blob_len) || - eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, - ¶ms->dh_blob_len)) { + ¶ms->private_key_blob_len)) { wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); return -1; } diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index c4019154..c8e2de0a 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -1473,11 +1473,11 @@ start: goto start; } - /* draft-ietf-emu-eap-tls13-13 Section 2.5 */ + /* RFC 9190 Section 2.5 */ if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 && *wpabuf_head_u8(in_decrypted) == 0) { wpa_printf(MSG_DEBUG, - "EAP-TTLS: ACKing EAP-TLS Commitment Message"); + "EAP-TLS: ACKing protected success indication (appl data 0x00)"); eap_peer_tls_reset_output(&data->ssl); wpabuf_free(in_decrypted); return 1; diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 61032cc0..2894cfbf 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -124,6 +124,9 @@ struct eap_config { * callback context. */ void *eap_sim_db_priv; + + struct crypto_rsa_key *imsi_privacy_key; + bool backend_auth; int eap_server; @@ -258,6 +261,10 @@ struct eap_config { unsigned int max_auth_rounds; unsigned int max_auth_rounds_short; + +#ifdef CONFIG_TESTING_OPTIONS + bool skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ }; struct eap_session_data { diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c index e9bf0300..5fb19e97 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -9,6 +9,7 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" #include "crypto/sha256.h" #include "crypto/crypto.h" #include "crypto/random.h" @@ -737,11 +738,8 @@ static void eap_aka_determine_identity(struct eap_sm *sm, sm->identity, sm->identity_len); username = sim_get_username(sm->identity, sm->identity_len); - if (username == NULL) { - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } + if (!username) + goto fail; if (eap_aka_check_identity_reauth(sm, data, username) > 0) { os_free(username); @@ -785,16 +783,87 @@ static void eap_aka_determine_identity(struct eap_sm *sm, username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); +#ifdef CRYPTO_RSA_OAEP_SHA256 + } else if (sm->identity_len > 1 && sm->identity[0] == '\0') { + char *enc_id, *pos, *end; + size_t enc_id_len; + u8 *decoded_id; + size_t decoded_id_len; + struct wpabuf *enc, *dec; + u8 *new_id; + + os_free(username); + if (!sm->cfg->imsi_privacy_key) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it"); + goto fail; + } + + enc_id = (char *) &sm->identity[1]; + end = (char *) &sm->identity[sm->identity_len]; + for (pos = enc_id; pos < end; pos++) { + if (*pos == ',') + break; + } + enc_id_len = pos - enc_id; + + wpa_hexdump_ascii(MSG_DEBUG, + "EAP-AKA: Encrypted permanent identity", + enc_id, enc_id_len); + decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len); + if (!decoded_id) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Could not base64 decode encrypted identity"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, + "EAP-AKA: Decoded encrypted permanent identity", + decoded_id, decoded_id_len); + enc = wpabuf_alloc_copy(decoded_id, decoded_id_len); + os_free(decoded_id); + if (!enc) + goto fail; + dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key, + enc); + wpabuf_free(enc); + if (!dec) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Failed to decrypt encrypted identity"); + goto fail; + } + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity", + wpabuf_head(dec), wpabuf_len(dec)); + username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec)); + if (!username) { + wpabuf_free(dec); + goto fail; + } + new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec)); + if (!new_id) { + wpabuf_free(dec); + goto fail; + } + os_free(sm->identity); + sm->identity = new_id; + sm->identity_len = wpabuf_len(dec); + wpabuf_free(dec); + os_strlcpy(data->permanent, username, sizeof(data->permanent)); + os_free(username); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'", username); os_free(username); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); + goto fail; return; } eap_aka_fullauth(sm, data); + return; + +fail: + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_aka_state(data, NOTIFICATION); } diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c index eac3245c..54406707 100644 --- a/src/eap_server/eap_server_eke.c +++ b/src/eap_server/eap_server_eke.c @@ -276,6 +276,7 @@ static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm, if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); + wpabuf_free(msg); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index f526e8bf..998d0e8a 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -56,6 +56,10 @@ struct eap_peap_data { }; +static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, + int vendor, enum eap_type eap_type); + + static const char * eap_peap_state_txt(int state) { switch (state) { @@ -558,10 +562,24 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " "starting Phase2"); eap_peap_state(data, PHASE2_START); + if (data->ssl.tls_v13 && data->ssl.tls_out && + wpabuf_len(data->ssl.tls_out) == 0) { + /* This can happen with TLS 1.3 when a new + * session ticket is not generated and the + * Finished message from the peer terminates + * Phase 1. */ + wpa_printf(MSG_DEBUG, + "EAP-PEAP: No pending data to send - move directly to Phase 2 ID query"); + eap_peap_state(data, PHASE2_ID); + eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF, + EAP_TYPE_IDENTITY); + goto phase2_id; + } } break; case PHASE2_ID: case PHASE2_METHOD: + phase2_id: wpabuf_free(data->ssl.tls_out); data->ssl.tls_out_pos = 0; data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c index 8a682896..1bcf26c4 100644 --- a/src/eap_server/eap_server_sim.c +++ b/src/eap_server/eap_server_sim.c @@ -9,6 +9,8 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" +#include "crypto/crypto.h" #include "crypto/random.h" #include "eap_server/eap_i.h" #include "eap_common/eap_sim_common.h" @@ -512,6 +514,73 @@ static void eap_sim_process_start(struct eap_sm *sm, username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); +#ifdef CRYPTO_RSA_OAEP_SHA256 + } else if (sm->identity_len > 1 && sm->identity[0] == '\0') { + char *enc_id, *pos, *end; + size_t enc_id_len; + u8 *decoded_id; + size_t decoded_id_len; + struct wpabuf *enc, *dec; + u8 *new_id; + + os_free(username); + if (!sm->cfg->imsi_privacy_key) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it"); + goto failed; + } + + enc_id = (char *) &sm->identity[1]; + end = (char *) &sm->identity[sm->identity_len]; + for (pos = enc_id; pos < end; pos++) { + if (*pos == ',') + break; + } + enc_id_len = pos - enc_id; + + wpa_hexdump_ascii(MSG_DEBUG, + "EAP-SIM: Encrypted permanent identity", + enc_id, enc_id_len); + decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len); + if (!decoded_id) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Could not base64 decode encrypted identity"); + goto failed; + } + wpa_hexdump(MSG_DEBUG, + "EAP-SIM: Decoded encrypted permanent identity", + decoded_id, decoded_id_len); + enc = wpabuf_alloc_copy(decoded_id, decoded_id_len); + os_free(decoded_id); + if (!enc) + goto failed; + dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key, + enc); + wpabuf_free(enc); + if (!dec) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Failed to decrypt encrypted identity"); + goto failed; + } + wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity", + wpabuf_head(dec), wpabuf_len(dec)); + username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec)); + if (!username) { + wpabuf_free(dec); + goto failed; + } + new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec)); + if (!new_id) { + wpabuf_free(dec); + goto failed; + } + os_free(sm->identity); + sm->identity = new_id; + sm->identity_len = wpabuf_len(dec); + wpabuf_free(dec); + os_strlcpy(data->permanent, username, sizeof(data->permanent)); + os_free(username); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } else { wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", username); diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c index 00a496f2..443c293c 100644 --- a/src/eap_server/eap_server_tls.c +++ b/src/eap_server/eap_server_tls.c @@ -1,5 +1,5 @@ /* - * hostapd / EAP-TLS (RFC 2716) + * hostapd / EAP-TLS (RFC 5216, RFC 9190) * Copyright (c) 2004-2008, Jouni Malinen * * This software may be distributed under the terms of the BSD license. @@ -306,6 +306,14 @@ static void eap_tls_process(struct eap_sm *sm, void *priv, wpa_printf(MSG_DEBUG, "EAP-TLS: Resuming previous session"); + + if (data->ssl.tls_v13 && data->ssl.tls_out) { + wpa_hexdump_buf(MSG_DEBUG, + "EAP-TLS: Additional data to be sent for TLS 1.3", + data->ssl.tls_out); + return; + } + eap_tls_state(data, SUCCESS); tls_connection_set_success_data_resumed(data->ssl.conn); /* TODO: Cache serial number with session and update EAP user diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index a9b53b1a..717af2e8 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -94,6 +94,11 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, if (data->tls_out_limit > 100) data->tls_out_limit -= 100; } + +#ifdef CONFIG_TESTING_OPTIONS + data->skip_prot_success = sm->cfg->skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ + return 0; } @@ -367,14 +372,14 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) sm->cfg->ssl_ctx, data->conn); /* - * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5 + * RFC 9190 Section 2.5 * * We need to signal the other end that TLS negotiation is done. We * can't send a zero-length application data message, so we send * application data which is one byte of zero. * * Note this is only done for when there is no application data to be - * sent. So this is done always for EAP-TLS but notibly not for PEAP + * sent. So this is done always for EAP-TLS but notably not for PEAP * even on resumption. */ if (data->tls_v13 && @@ -390,8 +395,15 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) break; /* fallthrough */ case EAP_TYPE_TLS: +#ifdef CONFIG_TESTING_OPTIONS + if (data->skip_prot_success) { + wpa_printf(MSG_INFO, + "TESTING: Do not send protected success indication"); + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpa_printf(MSG_DEBUG, - "EAP-TLS: Send Commitment Message"); + "EAP-TLS: Send protected success indication (appl data 0x00)"); plain = wpabuf_alloc(1); if (!plain) diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h index b0723a1f..ad28c796 100644 --- a/src/eap_server/eap_tls_common.h +++ b/src/eap_server/eap_tls_common.h @@ -55,6 +55,8 @@ struct eap_ssl_data { * tls_v13 - Whether TLS v1.3 or newer is used */ int tls_v13; + + bool skip_prot_success; /* testing behavior only for TLS v1.3 */ }; diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h index 5fe89c64..61b7039d 100644 --- a/src/eapol_auth/eapol_auth_sm.h +++ b/src/eapol_auth/eapol_auth_sm.h @@ -23,6 +23,7 @@ struct eapol_auth_config { size_t eap_req_id_text_len; int erp_send_reauth_start; char *erp_domain; /* a copy of this will be allocated */ + bool eap_skip_prot_success; /* Opaque context pointer to owner data for callback functions */ void *ctx; diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index 7d21f688..a2036063 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -508,7 +508,7 @@ void p2p_copy_channels(struct p2p_channels *dst, return; } - for (i = 0, j = 0; i < P2P_MAX_REG_CLASSES; i++) { + for (i = 0, j = 0; i < src->reg_classes; i++) { if (is_6ghz_op_class(src->reg_class[i].reg_class)) continue; os_memcpy(&dst->reg_class[j], &src->reg_class[i], diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c index cf41d8db..2bf3e8e8 100644 --- a/src/pae/ieee802_1x_cp.c +++ b/src/pae/ieee802_1x_cp.c @@ -20,7 +20,7 @@ #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm #define STATE_MACHINE_DEBUG_PREFIX "CP" -static u64 default_cs_id = CS_ID_GCM_AES_128; +static u64 cs_id[] = { CS_ID_GCM_AES_128, CS_ID_GCM_AES_256 }; /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */ enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE }; @@ -210,7 +210,6 @@ SM_STATE(CP, SECURED) sm->replay_protect = sm->kay->macsec_replay_protect; sm->validate_frames = sm->kay->macsec_validate; - /* NOTE: now no other than default cipher suite (AES-GCM-128) */ sm->current_cipher_suite = sm->cipher_suite; secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite); @@ -473,8 +472,8 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) sm->orx = false; sm->otx = false; - sm->current_cipher_suite = default_cs_id; - sm->cipher_suite = default_cs_id; + sm->current_cipher_suite = cs_id[kay->macsec_csindex]; + sm->cipher_suite = cs_id[kay->macsec_csindex]; sm->cipher_offset = CONFIDENTIALITY_OFFSET_0; sm->confidentiality_offset = sm->cipher_offset; sm->transmit_delay = MKA_LIFE_TIME; @@ -491,6 +490,7 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); secy_cp_control_confidentiality_offset(sm->kay, sm->confidentiality_offset); + secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite); SM_STEP_RUN(CP); diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c index 657de93a..a1f8ae93 100644 --- a/src/pae/ieee802_1x_kay.c +++ b/src/pae/ieee802_1x_kay.c @@ -221,8 +221,16 @@ ieee802_1x_mka_dump_dist_sak_body(struct ieee802_1x_mka_dist_sak_body *body) wpa_printf(MSG_DEBUG, "\tKey Number............: %d", be_to_host32(body->kn)); - /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */ - wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24); + if (body_len == 28) { + wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", + body->sak, 24); + } else if (body_len > CS_ID_LEN - sizeof(body->kn)) { + wpa_hexdump(MSG_DEBUG, "\tMACsec Cipher Suite...:", + body->sak, CS_ID_LEN); + wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", + body->sak + CS_ID_LEN, + body_len - CS_ID_LEN - sizeof(body->kn)); + } } @@ -3456,7 +3464,8 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf, struct ieee802_1x_kay * ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, bool macsec_replay_protect, u32 macsec_replay_window, - u16 port, u8 priority, const char *ifname, const u8 *addr) + u16 port, u8 priority, u32 macsec_csindex, + const char *ifname, const u8 *addr) { struct ieee802_1x_kay *kay; @@ -3493,7 +3502,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, kay->dist_time = 0; kay->pn_exhaustion = PENDING_PN_EXHAUSTION; - kay->macsec_csindex = DEFAULT_CS_INDEX; + kay->macsec_csindex = macsec_csindex; kay->mka_algindex = DEFAULT_MKA_ALG_INDEX; kay->mka_version = MKA_VERSION_ID; diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h index 1d3c2acb..11cf7b75 100644 --- a/src/pae/ieee802_1x_kay.h +++ b/src/pae/ieee802_1x_kay.h @@ -240,7 +240,8 @@ u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci); struct ieee802_1x_kay * ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, bool macsec_replay_protect, u32 macsec_replay_window, - u16 port, u8 priority, const char *ifname, const u8 *addr); + u16 port, u8 priority, u32 macsec_csindex, + const char *ifname, const u8 *addr); void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay); struct ieee802_1x_mka_participant * diff --git a/src/radius/radius.c b/src/radius/radius.c index be16e27b..a6422806 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen + * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -159,7 +159,8 @@ static const char *radius_code_string(u8 code) struct radius_attr_type { - u8 type; + u16 type; /* 0..255 for basic types; + * (241 << 8) | for extended types */ char *name; enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, @@ -260,11 +261,31 @@ static const struct radius_attr_type radius_attrs[] = RADIUS_ATTR_HEXDUMP }, { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6", + RADIUS_ATTR_UNDIST }, }; #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) -static const struct radius_attr_type *radius_get_attr_type(u8 type) +static const struct radius_attr_type * radius_get_attr_type(u16 type) { size_t i; @@ -277,23 +298,60 @@ static const struct radius_attr_type *radius_get_attr_type(u8 type) } +static bool radius_is_long_ext_type(u8 type) +{ + return type == RADIUS_ATTR_LONG_EXT_TYPE_1 || + type == RADIUS_ATTR_LONG_EXT_TYPE_2; +} + + +static bool radius_is_ext_type(u8 type) +{ + return type >= RADIUS_ATTR_EXT_TYPE_1 && + type <= RADIUS_ATTR_LONG_EXT_TYPE_2; +} + + static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) { + struct radius_attr_hdr_ext *ext = NULL; const struct radius_attr_type *attr; int len; unsigned char *pos; char buf[1000]; - attr = radius_get_attr_type(hdr->type); - - wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", - hdr->type, attr ? attr->name : "?Unknown?", hdr->length); - - if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) + if (hdr->length < sizeof(struct radius_attr_hdr)) return; - len = hdr->length - sizeof(struct radius_attr_hdr); - pos = (unsigned char *) (hdr + 1); + if (radius_is_ext_type(hdr->type)) { + if (hdr->length < 4) { + wpa_printf(MSG_INFO, + " Invalid attribute %d (too short for extended type)", + hdr->type); + return; + } + + ext = (struct radius_attr_hdr_ext *) hdr; + } + + if (ext) { + attr = radius_get_attr_type((ext->type << 8) | ext->ext_type); + wpa_printf(MSG_INFO, " Attribute %d.%d (%s) length=%d", + ext->type, ext->ext_type, + attr ? attr->name : "?Unknown?", ext->length); + pos = (unsigned char *) (ext + 1); + len = ext->length - sizeof(struct radius_attr_hdr_ext); + } else { + attr = radius_get_attr_type(hdr->type); + wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", + hdr->type, attr ? attr->name : "?Unknown?", + hdr->length); + pos = (unsigned char *) (hdr + 1); + len = hdr->length - sizeof(struct radius_attr_hdr); + } + + if (!attr) + return; switch (attr->data_type) { case RADIUS_ATTR_TEXT: @@ -627,22 +685,54 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg, } -struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, - const u8 *data, size_t data_len) +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, + const u8 *data, size_t data_len) { - size_t buf_needed; - struct radius_attr_hdr *attr; + size_t buf_needed, max_len; + struct radius_attr_hdr *attr = NULL; + struct radius_attr_hdr_ext *ext; + u8 ext_type = 0; if (TEST_FAIL()) return NULL; - if (data_len > RADIUS_MAX_ATTR_LEN) { - wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)", - (unsigned long) data_len); - return NULL; + if (type > 255) { + if (!radius_is_ext_type(type >> 8)) { + wpa_printf(MSG_ERROR, + "%s: Undefined extended type %d.%d", + __func__, type >> 8, type & 0xff); + return NULL; + } + ext_type = type & 0xff; + type >>= 8; + } else if (radius_is_ext_type(type)) { + wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d", + __func__, type); } - buf_needed = sizeof(*attr) + data_len; + if (radius_is_long_ext_type(type)) { + size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1; + size_t plen = 255 - hdr_len; + size_t num; + + max_len = 4096; + num = (data_len + plen - 1) / plen; + if (num == 0) + num = 1; + buf_needed = num * hdr_len + data_len; + } else if (radius_is_ext_type(type)) { + max_len = RADIUS_MAX_EXT_ATTR_LEN; + buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len; + } else { + max_len = RADIUS_MAX_ATTR_LEN; + buf_needed = sizeof(*attr) + data_len; + } + if (data_len > max_len) { + wpa_printf(MSG_ERROR, + "%s: too long attribute (%zu > %zu bytes)", + __func__, data_len, max_len); + return NULL; + } if (wpabuf_tailroom(msg->buf) < buf_needed) { /* allocate more space for message buffer */ @@ -651,13 +741,44 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, msg->hdr = wpabuf_mhead(msg->buf); } - attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); - attr->type = type; - attr->length = sizeof(*attr) + data_len; - wpabuf_put_data(msg->buf, data, data_len); + if (radius_is_long_ext_type(type)) { + size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1; + size_t alen; - if (radius_msg_add_attr_to_array(msg, attr)) - return NULL; + do { + alen = data_len > plen ? plen : data_len; + ext = wpabuf_put(msg->buf, + sizeof(struct radius_attr_hdr_ext)); + if (!attr) + attr = (struct radius_attr_hdr *) ext; + ext->type = type; + ext->length = sizeof(*ext) + 1 + alen; + ext->ext_type = ext_type; + wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0); + wpabuf_put_data(msg->buf, data, data_len); + data += alen; + data_len -= alen; + if (radius_msg_add_attr_to_array( + msg, (struct radius_attr_hdr *) ext)) + return NULL; + } while (data_len > 0); + } else if (radius_is_ext_type(type)) { + ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext)); + attr = (struct radius_attr_hdr *) ext; + ext->type = type; + ext->length = sizeof(*ext) + data_len; + ext->ext_type = ext_type; + wpabuf_put_data(msg->buf, data, data_len); + if (radius_msg_add_attr_to_array(msg, attr)) + return NULL; + } else { + attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); + attr->type = type; + attr->length = sizeof(*attr) + data_len; + wpabuf_put_data(msg->buf, data, data_len); + if (radius_msg_add_attr_to_array(msg, attr)) + return NULL; + } return attr; } @@ -1285,6 +1406,28 @@ int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, } +int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, + u8 vendor_type, const u8 *data, size_t len) +{ + struct radius_attr_hdr *attr; + u8 *buf, *pos; + size_t alen; + + alen = 4 + 1 + len; + buf = os_malloc(alen); + if (!buf) + return 0; + pos = buf; + WPA_PUT_BE32(pos, vendor_id); + pos += 4; + *pos++ = vendor_type; + os_memcpy(pos, data, len); + attr = radius_msg_add_attr(msg, type, buf, alen); + os_free(buf); + return attr != NULL; +} + + int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len, diff --git a/src/radius/radius.h b/src/radius/radius.h index fb814818..177c64a6 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen + * Copyright (c) 2002-2009, 2012, 2014-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -46,7 +46,15 @@ struct radius_attr_hdr { /* followed by length-2 octets of attribute value */ } STRUCT_PACKED; +struct radius_attr_hdr_ext { + u8 type; + u8 length; /* including this header */ + u8 ext_type; + /* followed by length-3 octets of attribute value */ +} STRUCT_PACKED; + #define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr)) +#define RADIUS_MAX_EXT_ATTR_LEN (255 - sizeof(struct radius_attr_hdr_ext)) enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_USER_PASSWORD = 2, @@ -113,6 +121,18 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_WLAN_GROUP_CIPHER = 187, RADIUS_ATTR_WLAN_AKM_SUITE = 188, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189, + RADIUS_ATTR_EXT_TYPE_1 = 241, + RADIUS_ATTR_EXT_TYPE_2 = 242, + RADIUS_ATTR_EXT_TYPE_3 = 243, + RADIUS_ATTR_EXT_TYPE_4 = 244, + RADIUS_ATTR_LONG_EXT_TYPE_1 = 245, + RADIUS_ATTR_LONG_EXT_TYPE_2 = 246, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1 = (241 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2 = (242 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3 = (243 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4 = (244 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5 = (245 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6 = (246 << 8) | 26, }; @@ -188,6 +208,13 @@ enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16, RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17 }; +/* FreeRADIUS vendor-specific attributes */ +#define RADIUS_VENDOR_ID_FREERADIUS 11344 +/* Extended-Vendor-Specific-5 (245.26; long extended header) */ +enum { + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE = 1, + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG = 2, +}; /* Hotspot 2.0 - WFA Vendor-specific RADIUS Attributes */ #define RADIUS_VENDOR_ID_WFA 40808 @@ -257,7 +284,7 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, size_t secret_len, int require_message_authenticator); -struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, const u8 *data, size_t data_len); struct radius_msg * radius_msg_parse(const u8 *data, size_t len); int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, @@ -284,6 +311,8 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *recv_key, size_t recv_key_len); int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, size_t len); +int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, + u8 vendor_type, const u8 *data, size_t len); int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len, diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 66a78066..00b7e846 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2024,6 +2024,13 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, u8 *rbuf, *key_mic; size_t kde_len = 0; +#ifdef CONFIG_TESTING_OPTIONS + if (sm->disable_eapol_g2_tx) { + wpa_printf(MSG_INFO, "TEST: Disable sending EAPOL-Key 2/2"); + return 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ + #ifdef CONFIG_OCV if (wpa_sm_ocv_enabled(sm)) kde_len = OCV_OCI_KDE_LEN; @@ -3381,6 +3388,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_OCI_FREQ_FILS_ASSOC: sm->oci_freq_override_fils_assoc = value; break; + case WPA_PARAM_DISABLE_EAPOL_G2_TX: + sm->disable_eapol_g2_tx = value; + break; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_DPP2 case WPA_PARAM_DPP_PFS: diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 2e84a226..00fa0bc3 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -118,6 +118,7 @@ enum wpa_sm_conf_params { WPA_PARAM_OCI_FREQ_EAPOL_G2, WPA_PARAM_OCI_FREQ_FT_ASSOC, WPA_PARAM_OCI_FREQ_FILS_ASSOC, + WPA_PARAM_DISABLE_EAPOL_G2_TX, }; struct rsn_supp_config { diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 6cdce321..579616fb 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -185,6 +185,7 @@ struct wpa_sm { unsigned int oci_freq_override_eapol_g2; unsigned int oci_freq_override_ft_assoc; unsigned int oci_freq_override_fils_assoc; + unsigned int disable_eapol_g2_tx; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_FILS diff --git a/src/utils/common.c b/src/utils/common.c index 2c127519..6acfcbd8 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -13,7 +13,7 @@ #include "common.h" -static int hex2num(char c) +int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; diff --git a/src/utils/common.h b/src/utils/common.h index 45f72bb3..435a9a84 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -477,6 +477,7 @@ int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); int hwaddr_compact_aton(const char *txt, u8 *addr); int hwaddr_aton2(const char *txt, u8 *addr); +int hex2num(char c); int hex2byte(const char *hex); int hexstr2bin(const char *hex, u8 *buf, size_t len); void inc_byte_array(u8 *counter, size_t len); diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h index d9fc925a..23e9ecd9 100644 --- a/src/utils/http-utils.h +++ b/src/utils/http-utils.h @@ -33,6 +33,7 @@ struct http_cert { size_t num_othername; struct http_logo *logo; size_t num_logo; + const char *url; }; int soap_init_client(struct http_ctx *ctx, const char *address, diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c index e62fbf96..30b07f23 100644 --- a/src/utils/http_curl.c +++ b/src/utils/http_curl.c @@ -64,6 +64,7 @@ struct http_ctx { X509 *peer_issuer_issuer; const char *last_err; + const char *url; }; @@ -871,6 +872,7 @@ static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert, X509 *cert, GENERAL_NAMES **names) { os_memset(hcert, 0, sizeof(*hcert)); + hcert->url = ctx->url ? ctx->url : ctx->svc_address; *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (*names) @@ -1617,23 +1619,23 @@ int http_download_file(struct http_ctx *ctx, const char *url, const char *fname, const char *ca_fname) { CURL *curl; - FILE *f; + FILE *f = NULL; CURLcode res; long http = 0; + int ret = -1; ctx->last_err = NULL; + ctx->url = url; wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)", url, fname, ca_fname); curl = curl_easy_init(); if (curl == NULL) - return -1; + goto fail; f = fopen(fname, "wb"); - if (f == NULL) { - curl_easy_cleanup(curl); - return -1; - } + if (!f) + goto fail; curl_easy_setopt(curl, CURLOPT_URL, url); if (ca_fname) { @@ -1655,9 +1657,7 @@ int http_download_file(struct http_ctx *ctx, const char *url, ctx->last_err = curl_easy_strerror(res); wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", ctx->last_err); - curl_easy_cleanup(curl); - fclose(f); - return -1; + goto fail; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); @@ -1665,15 +1665,19 @@ int http_download_file(struct http_ctx *ctx, const char *url, if (http != 200) { ctx->last_err = "HTTP download failed"; wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); - curl_easy_cleanup(curl); - fclose(f); - return -1; + goto fail; } - curl_easy_cleanup(curl); - fclose(f); + ret = 0; - return 0; +fail: + ctx->url = NULL; + if (curl) + curl_easy_cleanup(curl); + if (f) + fclose(f); + + return ret; } @@ -1686,16 +1690,17 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, { long http = 0; CURLcode res; - char *ret; + char *ret = NULL; CURL *curl; struct curl_slist *curl_hdr = NULL; ctx->last_err = NULL; + ctx->url = url; wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url); curl = setup_curl_post(ctx, url, ca_fname, username, password, client_cert, client_key); if (curl == NULL) - return NULL; + goto fail; if (content_type) { char ct[200]; @@ -1715,8 +1720,7 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, ctx->last_err = curl_easy_strerror(res); wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", ctx->last_err); - free_curl_buf(ctx); - return NULL; + goto fail; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); @@ -1724,12 +1728,11 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, if (http != 200) { ctx->last_err = "HTTP POST failed"; wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http); - free_curl_buf(ctx); - return NULL; + goto fail; } if (ctx->curl_buf == NULL) - return NULL; + goto fail; ret = ctx->curl_buf; if (resp_len) @@ -1739,6 +1742,9 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret); +fail: + free_curl_buf(ctx); + ctx->url = NULL; return ret; } diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp index 0d088bba..db113875 100644 --- a/wpa_supplicant/Android.bp +++ b/wpa_supplicant/Android.bp @@ -301,7 +301,6 @@ filegroup { "src/common/sae_pk.c", "src/common/wpa_common.c", "src/crypto/aes-ctr.c", - "src/crypto/aes-omac1.c", "src/crypto/aes-siv.c", "src/crypto/crypto_openssl.c", "src/crypto/dh_groups.c", diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index cdf89432..d1436e2b 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -119,7 +119,6 @@ endif ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= -CONFIG_OPENSSL_CMAC=y endif OBJS = config.c @@ -515,6 +514,9 @@ OBJS += src/eap_peer/eap_tls.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_TLSV1_3 +L_CFLAGS += -DEAP_TLSV1_3 +endif endif ifdef CONFIG_EAP_UNAUTH_TLS @@ -775,6 +777,7 @@ OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c CONFIG_IEEE8021X_EAPOL=y NEED_ECC=y NEED_DRAGONFLY=y +MS_FUNCS=y endif ifdef CONFIG_EAP_EKE @@ -945,6 +948,9 @@ endif ifdef CONFIG_IEEE80211AX OBJS += src/ap/ieee802_11_he.c endif +ifdef CONFIG_IEEE80211BE +OBJS += src/ap/ieee802_11_eht.c +endif ifdef CONFIG_WNM_AP L_CFLAGS += -DCONFIG_WNM_AP OBJS += src/ap/wnm_ap.c @@ -967,6 +973,10 @@ OBJS += src/eap_server/eap_server_methods.c ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +L_CFLAGS += -DCONFIG_IEEE80211BE +endif ifdef CONFIG_IEEE80211AX L_CFLAGS += -DCONFIG_IEEE80211AX endif @@ -1099,6 +1109,7 @@ L_CFLAGS += -DCONFIG_TLSV12 endif ifeq ($(CONFIG_TLS), openssl) +L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ifdef TLS_FUNCS L_CFLAGS += -DEAP_TLS_OPENSSL OBJS += src/crypto/tls_openssl.c @@ -1303,9 +1314,7 @@ ifdef NEED_AES_ENCBLOCK AESOBJS += src/crypto/aes-encblock.c endif NEED_AES_ENC=y -ifdef CONFIG_OPENSSL_CMAC -L_CFLAGS += -DCONFIG_OPENSSL_CMAC -else +ifneq ($(CONFIG_TLS), openssl) AESOBJS += src/crypto/aes-omac1.c endif ifdef NEED_AES_WRAP @@ -1399,6 +1408,17 @@ endif endif endif +ifdef CONFIG_SAE +ifdef NEED_SHA384 +# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled. +NEED_HMAC_SHA384_KDF=y +endif +ifdef NEED_SHA512 +# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled. +NEED_HMAC_SHA512_KDF=y +endif +endif + SHA256OBJS = # none by default L_CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 18ffbcb9..1c6911b9 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1,24 +1,29 @@ BINALL=wpa_supplicant wpa_cli -ifndef CONFIG_NO_WPA_PASSPHRASE -BINALL += wpa_passphrase -endif - ALL = $(BINALL) ALL += systemd/wpa_supplicant.service ALL += systemd/wpa_supplicant@.service ALL += systemd/wpa_supplicant-nl80211@.service ALL += systemd/wpa_supplicant-wired@.service ALL += dbus/fi.w1.wpa_supplicant1.service -ifdef CONFIG_BUILD_WPA_CLIENT_SO -ALL += libwpa_client.so -endif EXTRA_TARGETS=dynamic_eap_methods CONFIG_FILE=.config include ../src/build.rules +ifdef CONFIG_BUILD_WPA_CLIENT_SO +# add the dependency this way to allow CONFIG_BUILD_WPA_CLIENT_SO +# being set in the config which is read by build.rules +_all: libwpa_client.so +endif + +ifndef CONFIG_NO_WPA_PASSPHRASE +# add the dependency this way to allow CONFIG_NO_WPA_PASSPHRASE +# being set in the config which is read by build.rules +_all: wpa_passphrase +endif + ifdef LIBS # If LIBS is set with some global build system defaults, clone those for # LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well. @@ -68,6 +73,9 @@ $(DESTDIR)$(BINDIR)/%: % install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL)) $(MAKE) -C ../src install +ifndef CONFIG_NO_WPA_PASSPHRASE + install -D wpa_passphrase $(DESTDIR)/$(BINDIR)/wpa_passphrase +endif ifdef CONFIG_BUILD_WPA_CLIENT_SO install -m 0644 -D libwpa_client.so $(DESTDIR)/$(LIBDIR)/libwpa_client.so install -m 0644 -D ../src/common/wpa_ctrl.h $(DESTDIR)/$(INCDIR)/wpa_ctrl.h @@ -79,7 +87,6 @@ endif ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= -CONFIG_OPENSSL_CMAC=y endif OBJS = config.o @@ -484,6 +491,9 @@ OBJS += ../src/eap_peer/eap_tls.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_TLSV1_3 +CFLAGS += -DEAP_TLSV1_3 +endif endif ifdef CONFIG_EAP_UNAUTH_TLS @@ -750,6 +760,7 @@ OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o CONFIG_IEEE8021X_EAPOL=y NEED_ECC=y NEED_DRAGONFLY=y +MS_FUNCS=y endif ifdef CONFIG_EAP_EKE @@ -939,6 +950,9 @@ endif ifdef CONFIG_IEEE80211AX OBJS += ../src/ap/ieee802_11_he.o endif +ifdef CONFIG_IEEE80211BE +OBJS += ../src/ap/ieee802_11_eht.o +endif ifdef CONFIG_WNM_AP CFLAGS += -DCONFIG_WNM_AP OBJS += ../src/ap/wnm_ap.o @@ -961,6 +975,10 @@ OBJS += ../src/eap_server/eap_server_methods.o ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +CFLAGS += -DCONFIG_IEEE80211BE +endif ifdef CONFIG_IEEE80211AX CFLAGS += -DCONFIG_IEEE80211AX endif @@ -1107,6 +1125,7 @@ LIBS_p += -lwolfssl -lm endif ifeq ($(CONFIG_TLS), openssl) +CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ifdef TLS_FUNCS CFLAGS += -DEAP_TLS_OPENSSL OBJS += ../src/crypto/tls_openssl.o @@ -1358,9 +1377,7 @@ ifdef NEED_AES_ENCBLOCK AESOBJS += ../src/crypto/aes-encblock.o endif NEED_AES_ENC=y -ifdef CONFIG_OPENSSL_CMAC -CFLAGS += -DCONFIG_OPENSSL_CMAC -else +ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-omac1.o @@ -1474,6 +1491,17 @@ endif endif endif +ifdef CONFIG_SAE +ifdef NEED_SHA384 +# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled. +NEED_HMAC_SHA384_KDF=y +endif +ifdef NEED_SHA512 +# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled. +NEED_HMAC_SHA512_KDF=y +endif +endif + SHA256OBJS = # none by default CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) @@ -2076,3 +2104,4 @@ clean: common-clean rm -f libwpa_client.a rm -f libwpa_client.so rm -f libwpa_test1 libwpa_test2 + rm -f wpa_passphrase diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index b076621d..a099a85b 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -168,6 +168,12 @@ Credentials can be pre-configured for automatic network selection: # milenage: Milenage parameters for SIM/USIM simulator in :: # format # +# imsi_privacy_key: IMSI privacy key (PEM encoded X.509v3 certificate) +# This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent +# identity (IMSI) to improve privacy. The X.509v3 certificate needs to +# include a 2048-bit RSA public key and this is from the operator who +# authenticates the SIM/USIM. +# # domain_suffix_match: Constraint for server domain name # If set, this FQDN is used as a suffix match requirement for the AAA # server certificate in SubjectAltName dNSName element(s). If a diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS index b884f67a..e902cc8c 100644 --- a/wpa_supplicant/README-WPS +++ b/wpa_supplicant/README-WPS @@ -24,8 +24,8 @@ not very secure. As such, use of WPS may not be suitable for environments that require secure network access without chance for allowing outsiders to gain access during the setup phase. -WPS uses following terms to describe the entities participating in the -network setup: +WPS uses the following terms to describe the entities participating +in the network setup: - access point: the WLAN access point - Registrar: a device that control a network and can authorize addition of new devices); this may be either in the AP ("internal @@ -55,22 +55,22 @@ wpa_supplicant configuration WPS is an optional component that needs to be enabled in wpa_supplicant build configuration (.config). Here is an example -configuration that includes WPS support and Linux nl80211 -based +configuration that includes WPS support and Linux nl80211-based driver interface: CONFIG_DRIVER_NL80211=y CONFIG_WPS=y If you want to enable WPS external registrar (ER) functionality, you -will also need to add following line: +will also need to add the following line: CONFIG_WPS_ER=y -Following parameter can be used to enable support for NFC config method: +The following parameter can be used to enable support for NFC config +method: CONFIG_WPS_NFC=y - WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for the device. This is configured in the runtime configuration for wpa_supplicant (if not set, UUID will be generated based on local MAC @@ -91,7 +91,6 @@ to allow configuration file updates: update_config=1 - External operations ------------------- @@ -118,7 +117,6 @@ entered at the Registrar to complete WPS registration. At that point, the client will be enrolled with credentials needed to connect to the AP to access the network. - If the client device does not have a display that could show the random PIN, a hardcoded PIN that is printed on a label can be used. wpa_supplicant is notified this with a control interface @@ -135,7 +133,6 @@ expiration timeout for the PIN in seconds. For example: wpa_cli wps_pin any 12345670 300 - If a random PIN is needed for a user interface, "wpa_cli wps_pin get" can be used to generate a new PIN without starting WPS negotiation. This random PIN can then be passed as an argument to another wps_pin @@ -154,7 +151,6 @@ At this point, the AP/Registrar has two minutes to complete WPS negotiation which will generate a new WPA PSK in the same way as the PIN method described above. - If the client wants to operate in the Registrar role to learn the current AP configuration and optionally, to configure an AP, wpa_supplicant is notified over the control interface, e.g., with @@ -218,7 +214,8 @@ option. When this is used, an external program is responsible for processing the credential attributes and updating wpa_supplicant configuration based on them. -Following control interface messages are sent out for external programs: +The following control interface messages are sent out for external +programs: WPS-CRED-RECEIVED For example: @@ -236,7 +233,7 @@ can be either over a wired or wireless connection). Separate wpa_supplicant process can be started for WPS ER operations. A special "none" driver can be used in such a case to indicate that no local network interface is actually controlled. For -example, following command could be used to start the ER: +example, the following command could be used to start the ER: wpa_supplicant -Dnone -c er.conf -ieth0 @@ -245,7 +242,6 @@ Sample er.conf: ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin device_name=WPS External Registrar - wpa_cli commands for ER functionality: wps_er_start [IP address] @@ -275,7 +271,6 @@ wps_er_config must be one of the following: OPEN WPAPSK WPA2PSK must be one of the following: NONE WEP TKIP CCMP - wps_er_pbc - accept an Enrollee PBC using External Registrar @@ -285,7 +280,6 @@ wps_er_pin [Enrollee MAC address] - if the MAC address of the enrollee is known, it should be configured to allow the AP to advertise list of authorized enrollees - WPS ER events: WPS_EVENT_ER_AP_ADD diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 0559822c..7b31d8e4 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1028,6 +1028,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, hapd_iface->extended_capa = wpa_s->extended_capa; hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; hapd_iface->extended_capa_len = wpa_s->extended_capa_len; + hapd_iface->drv_max_acl_mac_addrs = wpa_s->drv_max_acl_mac_addrs; wpa_s->ap_iface->conf = conf = hostapd_config_defaults(); if (conf == NULL) { @@ -1105,6 +1106,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, hapd_iface->bss[i]->ext_eapol_frame_io = wpa_s->ext_eapol_frame_io; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_WNM_AP + if (ssid->mode == WPAS_MODE_AP) + hapd_iface->bss[i]->conf->bss_transition = 1; +#endif /* CONFIG_WNM_AP */ } os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN); @@ -1564,6 +1570,183 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, return pos - buf; } + +#ifdef CONFIG_WNM_AP + +int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s, + const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + return hostapd_ctrl_iface_disassoc_imminent(hapd, buf); +} + + +int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + return hostapd_ctrl_iface_ess_disassoc(hapd, buf); +} + + +int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + return hostapd_ctrl_iface_bss_tm_req(hapd, buf); +} + +#endif /* CONFIG_WNM_AP */ + + +int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, + const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + hapd->conf->macaddr_acl = acl_type; + + if (acl_type == ACCEPT_UNLESS_DENIED) + return hostapd_ctrl_iface_acl_add_mac(&hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, + buf); + if (acl_type == DENY_UNLESS_ACCEPTED) + return hostapd_ctrl_iface_acl_add_mac( + &hapd->conf->accept_mac, + &hapd->conf->num_accept_mac, buf); + + return -1; +} + + +int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, + const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + hapd->conf->macaddr_acl = acl_type; + + if (acl_type == ACCEPT_UNLESS_DENIED) + return hostapd_ctrl_iface_acl_del_mac(&hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, + buf); + if (acl_type == DENY_UNLESS_ACCEPTED) + return hostapd_ctrl_iface_acl_del_mac( + &hapd->conf->accept_mac, &hapd->conf->num_accept_mac, + buf); + + return -1; +} + + +int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, char *buf, + size_t buflen) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + if (acl_type == ACCEPT_UNLESS_DENIED) + return hostapd_ctrl_iface_acl_show_mac(hapd->conf->deny_mac, + hapd->conf->num_deny_mac, + buf, buflen); + if (acl_type == DENY_UNLESS_ACCEPTED) + return hostapd_ctrl_iface_acl_show_mac( + hapd->conf->accept_mac, hapd->conf->num_accept_mac, + buf, buflen); + + return -1; +} + + +void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return; + + hapd->conf->macaddr_acl = acl_type; + + if (acl_type == ACCEPT_UNLESS_DENIED) + hostapd_ctrl_iface_acl_clear_list(&hapd->conf->deny_mac, + &hapd->conf->num_deny_mac); + else if (acl_type == DENY_UNLESS_ACCEPTED) + hostapd_ctrl_iface_acl_clear_list(&hapd->conf->accept_mac, + &hapd->conf->num_accept_mac); +} + + +int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + return hostapd_disassoc_deny_mac(hapd); +} + + +int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + return hostapd_disassoc_accept_mac(hapd); +} + + +int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + return hostapd_set_acl(hapd); +} + #endif /* CONFIG_CTRL_IFACE */ diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 7bc1b781..ccd3e7b5 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -10,6 +10,8 @@ #ifndef AP_H #define AP_H +enum macaddr_acl; + int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s); @@ -38,6 +40,22 @@ int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s, const char *txtaddr); int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen, int verbose); +int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s, + const char *buf); +int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf); +int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf); +int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, const char *buf); +int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, const char *buf); +int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, char *buf, + size_t buflen); +void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type); +int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s); +int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s); +int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s); void ap_tx_status(void *ctx, const u8 *addr, const u8 *buf, size_t len, int ack); void ap_eapol_tx_status(void *ctx, const u8 *dst, diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index e13783ce..429c6e75 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -291,6 +291,7 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, dst->noise = src->noise; dst->level = src->level; dst->tsf = src->tsf; + dst->beacon_newer = src->beacon_newer; dst->est_throughput = src->est_throughput; dst->snr = src->snr; diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 4078b9b9..146aaee7 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -108,6 +108,8 @@ struct wpa_bss { int level; /** Timestamp of last Beacon/Probe Response frame */ u64 tsf; + /** Whether the Beacon frame data is known to be newer */ + bool beacon_newer; /** Time of the last update (i.e., Beacon or Probe Response RX) */ struct os_reltime last_update; /** Estimated throughput in kbps */ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index f344e1db..c8844bbb 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2451,7 +2451,6 @@ static const struct parse_data ssid_fields[] = { { 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) }, @@ -2462,7 +2461,6 @@ static const struct parse_data ssid_fields[] = { { 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) }, @@ -2490,7 +2488,6 @@ static const struct parse_data ssid_fields[] = { { 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) }, @@ -2506,6 +2503,7 @@ static const struct parse_data ssid_fields[] = { { INTe(machine_ocsp, machine_cert.ocsp) }, { INT(eapol_flags) }, { INTe(sim_num, sim_num) }, + { STRe(imsi_privacy_key, imsi_privacy_key) }, { STRe(openssl_ciphers, openssl_ciphers) }, { INTe(erp, erp) }, #endif /* IEEE8021X_EAPOL */ @@ -2612,6 +2610,7 @@ static const struct parse_data ssid_fields[] = { { INT(macsec_replay_window) }, { INT_RANGE(macsec_port, 1, 65534) }, { INT_RANGE(mka_priority, 0, 255) }, + { INT_RANGE(macsec_csindex, 0, 1) }, { FUNC_KEY(mka_cak) }, { FUNC_KEY(mka_ckn) }, #endif /* CONFIG_MACSEC */ @@ -2753,7 +2752,6 @@ static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert) 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); @@ -2773,6 +2771,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap) bin_clear_free(eap->identity, eap->identity_len); os_free(eap->anonymous_identity); os_free(eap->imsi_identity); + os_free(eap->imsi_privacy_key); os_free(eap->machine_identity); bin_clear_free(eap->password, eap->password_len); bin_clear_free(eap->machine_password, eap->machine_password_len); @@ -2876,6 +2875,7 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->req_conn_capab_port[i]); os_free(cred->req_conn_capab_port); os_free(cred->req_conn_capab_proto); + os_free(cred->imsi_privacy_key); os_free(cred); } @@ -3155,6 +3155,26 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) } +static const char *removed_fields[] = { + "dh_file", + "dh_file2", + "machine_dh_file", + NULL +}; + +static bool removed_field(const char *field) +{ + int i; + + for (i = 0; removed_fields[i]; i++) { + if (os_strcmp(field, removed_fields[i]) == 0) + return true; + } + + return false; +} + + /** * wpa_config_set - Set a variable in network configuration * @ssid: Pointer to network configuration data @@ -3203,6 +3223,12 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, break; } if (i == NUM_SSID_FIELDS) { + if (removed_field(var)) { + wpa_printf(MSG_INFO, + "Line %d: Ignore removed configuration field '%s'", + line, var); + return ret; + } if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown network field " "'%s'.", line, var); @@ -3400,8 +3426,11 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) void wpa_config_update_psk(struct wpa_ssid *ssid) { #ifndef CONFIG_NO_PBKDF2 - pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, - ssid->psk, PMK_LEN); + if (pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, + ssid->psk, PMK_LEN) != 0) { + wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()"); + return; + } wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", ssid->psk, PMK_LEN); ssid->psk_set = 1; @@ -3882,6 +3911,12 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "imsi_privacy_key") == 0) { + os_free(cred->imsi_privacy_key); + cred->imsi_privacy_key = val; + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); @@ -4032,6 +4067,9 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) if (os_strcmp(var, "imsi") == 0) return alloc_strdup(cred->imsi); + if (os_strcmp(var, "imsi_privacy_key") == 0) + return alloc_strdup(cred->imsi_privacy_key); + if (os_strcmp(var, "milenage") == 0) { if (!(cred->milenage)) return NULL; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 696fb38e..77d6ab5f 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -181,6 +181,16 @@ struct wpa_cred { */ char *milenage; + /** + * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate) + * + * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent + * identity (IMSI) to improve privacy. The X.509v3 certificate needs to + * include a 2048-bit RSA public key and this is from the operator who + * authenticates the SIM/USIM. + */ + char *imsi_privacy_key; + /** * engine - Use an engine for private key operations */ diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 778da459..978cc6a2 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -297,8 +297,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) struct wpa_ssid *ssid, *tail, *head; struct wpa_cred *cred, *cred_tail, *cred_head; struct wpa_config *config; - int id = 0; - int cred_id = 0; + static int id = 0; + static int cred_id = 0; if (name == NULL) return NULL; @@ -699,7 +699,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(client_cert); STR(private_key); STR(private_key_passwd); - STR(dh_file); STR(subject_match); STR(check_cert_subject); STR(altsubject_match); @@ -710,7 +709,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(client_cert2); STR(private_key2); STR(private_key2_passwd); - STR(dh_file2); STR(subject_match2); STR(check_cert_subject2); STR(altsubject_match2); @@ -721,7 +719,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) 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); @@ -810,6 +807,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(macsec_replay_window); INT(macsec_port); INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER); + INT(macsec_csindex); #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 INT(update_identifier); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index dd8b1d99..4d3d1142 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -910,6 +910,13 @@ struct wpa_ssid { */ int mka_priority; + /** + * macsec_csindex - Cipher suite index for MACsec + * + * Range: 0-1 (default: 0) + */ + int macsec_csindex; + /** * mka_ckn - MKA pre-shared CKN */ diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index 1b7f96ed..b27c6cf3 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -905,7 +905,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) STR(client_cert); STR(private_key); STR(private_key_passwd); - STR(dh_file); STR(subject_match); STR(check_cert_subject); STR(altsubject_match); @@ -914,7 +913,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) STR(client_cert2); STR(private_key2); STR(private_key2_passwd); - STR(dh_file2); STR(subject_match2); STR(check_cert_subject2); STR(altsubject_match2); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index dc6c772f..e8a81182 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -674,6 +674,9 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { os_free(wpa_s->dpp_configurator_params); wpa_s->dpp_configurator_params = os_strdup(value); +#ifdef CONFIG_DPP2 + dpp_controller_set_params(wpa_s->dpp, value); +#endif /* CONFIG_DPP2 */ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { wpa_s->dpp_init_max_tries = atoi(value); } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { @@ -836,6 +839,11 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->disable_scs_support = !!atoi(value); } else if (os_strcasecmp(cmd, "disable_mscs_support") == 0) { wpa_s->disable_mscs_support = !!atoi(value); + } else if (os_strcasecmp(cmd, "disable_eapol_g2_tx") == 0) { + wpa_s->disable_eapol_g2_tx = !!atoi(value); + /* Populate value to wpa_sm if already associated. */ + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX, + wpa_s->disable_eapol_g2_tx); #ifdef CONFIG_DPP } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { os_free(wpa_s->dpp_config_obj_override); @@ -2306,11 +2314,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, if (wpa_s->connection_set && (wpa_s->connection_ht || wpa_s->connection_vht || - wpa_s->connection_he)) { + wpa_s->connection_he || wpa_s->connection_eht)) { ret = os_snprintf(pos, end - pos, "wifi_generation=%u\n", - wpa_s->connection_he ? 6 : - (wpa_s->connection_vht ? 5 : 4)); + wpa_s->connection_eht ? 7 : + (wpa_s->connection_he ? 6 : + (wpa_s->connection_vht ? 5 : 4))); if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; @@ -8539,6 +8548,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->oci_freq_override_ft_assoc = 0; wpa_s->oci_freq_override_fils_assoc = 0; wpa_s->oci_freq_override_wnm_sleep = 0; + wpa_s->disable_eapol_g2_tx = 0; #ifdef CONFIG_DPP os_free(wpa_s->dpp_config_obj_override); wpa_s->dpp_config_obj_override = NULL; @@ -8592,6 +8602,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0) wpas_restore_permanent_mac_addr(wpa_s); + + wpa_s->conf->ignore_old_scan_res = 0; } @@ -9984,8 +9996,9 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s, int flow_id = 0; bool protection = false; u8 twt_channel = 0; - u8 control = BIT(4); /* Control field (IEEE P802.11ax/D8.0 Figure - * 9-687): B4 = TWT Information Frame Disabled */ + u8 control = BIT(4); /* Control field (IEEE Std 802.11ax-2021, + * Figure 9-687 - Control field format): + * B4 = TWT Information Frame Disabled */ const char *tok_s; tok_s = os_strstr(cmd, " dialog="); @@ -10687,7 +10700,7 @@ fail: #endif /* CONFIG_FILS */ -static int wpas_ctrl_cmd_debug_level(const char *cmd) +int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || os_strncmp(cmd, "BSS ", 4) == 0 || @@ -12019,6 +12032,58 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { if (wpas_ap_update_beacon(wpa_s)) reply_len = -1; + } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) { + if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_add_mac(wpa_s, + DENY_UNLESS_ACCEPTED, + buf + 19) || + ap_ctrl_iface_set_acl(wpa_s)) + reply_len = -1; + } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_del_mac(wpa_s, + DENY_UNLESS_ACCEPTED, + buf + 19) || + ap_ctrl_iface_set_acl(wpa_s) || + ap_ctrl_iface_disassoc_accept_mac(wpa_s)) + reply_len = -1; + } else if (os_strcmp(buf + 11, "SHOW") == 0) { + reply_len = ap_ctrl_iface_acl_show_mac( + wpa_s, DENY_UNLESS_ACCEPTED, + reply, reply_size); + } else if (os_strcmp(buf + 11, "CLEAR") == 0) { + ap_ctrl_iface_acl_clear_list(wpa_s, + DENY_UNLESS_ACCEPTED); + if (ap_ctrl_iface_set_acl(wpa_s) || + ap_ctrl_iface_disassoc_accept_mac(wpa_s)) + reply_len = -1; + } else { + reply_len = -1; + } + } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) { + if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_add_mac(wpa_s, + ACCEPT_UNLESS_DENIED, + buf + 17) || + ap_ctrl_iface_set_acl(wpa_s) || + ap_ctrl_iface_disassoc_deny_mac(wpa_s)) + reply_len = -1; + } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_del_mac(wpa_s, + ACCEPT_UNLESS_DENIED, + buf + 17) || + ap_ctrl_iface_set_acl(wpa_s)) + reply_len = -1; + } else if (os_strcmp(buf + 9, "SHOW") == 0) { + reply_len = ap_ctrl_iface_acl_show_mac( + wpa_s, ACCEPT_UNLESS_DENIED, reply, reply_size); + } else if (os_strcmp(buf + 9, "CLEAR") == 0) { + ap_ctrl_iface_acl_clear_list(wpa_s, + ACCEPT_UNLESS_DENIED); + if (ap_ctrl_iface_set_acl(wpa_s)) + reply_len = -1; + } else { + reply_len = -1; + } #endif /* CONFIG_AP */ } else if (os_strcmp(buf, "SUSPEND") == 0) { wpas_notify_suspend(wpa_s->global); @@ -12114,6 +12179,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) reply_len = -1; #endif /* CONFIG_WNM */ +#ifdef CONFIG_WNM_AP + } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { + if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18)) + reply_len = -1; + } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { + if (ap_ctrl_iface_ess_disassoc(wpa_s, buf + 13)) + reply_len = -1; + } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { + if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11)) + reply_len = -1; +#endif /* CONFIG_WNM_AP */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { @@ -12312,6 +12388,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) { + if (dpp_configurator_set(wpa_s->dpp, buf + 20) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) { if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0) reply_len = -1; diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h index dfbd25a0..9842ea1e 100644 --- a/wpa_supplicant/ctrl_iface.h +++ b/wpa_supplicant/ctrl_iface.h @@ -122,6 +122,8 @@ void wpa_supplicant_global_ctrl_iface_deinit( void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s); +int wpas_ctrl_cmd_debug_level(const char *cmd); + #else /* CONFIG_CTRL_IFACE */ static inline struct ctrl_iface_priv * diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 1cbf7fa2..1178f406 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -337,6 +337,9 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, else reply_len = 2; } else { + sockaddr_print(wpas_ctrl_cmd_debug_level(buf), + "Control interface recv command from:", + &from, fromlen); reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, &reply_len); } diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 639573da..2052873d 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -178,6 +178,9 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, else reply_len = 2; } else { + sockaddr_print(wpas_ctrl_cmd_debug_level(buf), + "Control interface recv command from:", + &from, fromlen); reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf, &reply_len); reply = reply_buf; diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 959a68b4..0b1002bf 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -1121,7 +1121,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { - const char *capabilities[13]; + const char *capabilities[14]; size_t num_items = 0; struct wpa_global *global = user_data; struct wpa_supplicant *wpa_s; @@ -1177,6 +1177,9 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( #endif /* CONFIG_SUITEB192 */ if (ext_key_id_supported) capabilities[num_items++] = "extended_key_id"; +#ifndef CONFIG_WEP + capabilities[num_items++] = "wep_disabled"; +#endif /* !CONFIG_WEP */ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, @@ -3951,7 +3954,7 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode( const char *auth_mode; char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; - if (wpa_s->wpa_state != WPA_COMPLETED) { + if (wpa_s->wpa_state <= WPA_SCANNING) { auth_mode = "INACTIVE"; } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 6208e9e5..95dc4e34 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -101,6 +101,9 @@ CONFIG_EAP_MSCHAPV2=y # EAP-TLS CONFIG_EAP_TLS=y +# Enable EAP-TLSv1.3 support by default (currently disabled unless explicitly +# enabled in network configuration) +#CONFIG_EAP_TLSV1_3=y # EAL-PEAP CONFIG_EAP_PEAP=y @@ -203,6 +206,9 @@ CONFIG_SMARTCARD=y # Support VHT overrides (disable VHT, mask MCS rates, etc.) #CONFIG_VHT_OVERRIDES=y +# Support HE overrides +#CONFIG_HE_OVERRIDES=y + # Development testing #CONFIG_EAPOL_TEST=y @@ -248,6 +254,9 @@ CONFIG_CTRL_IFACE=y # Simultaneous Authentication of Equals (SAE), WPA3-Personal CONFIG_SAE=y +# SAE Public Key, WPA3-Personal +#CONFIG_SAE_PK=y + # Disable scan result processing (ap_scan=1) to save code size by about 1 kB. # This can be used if ap_scan=1 mode is never enabled. #CONFIG_NO_SCAN_PROCESSING=y @@ -474,6 +483,16 @@ CONFIG_DEBUG_SYSLOG=y # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) CONFIG_IEEE80211AC=y +# IEEE 802.11ax HE support (mainly for AP mode) +CONFIG_IEEE80211AX=y + +# IEEE 802.11be EHT support (mainly for AP mode) +# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE. +# Note: This is experimental and work in progress. The definitions are still +# subject to change and this should not be expected to interoperate with the +# final IEEE 802.11be version. +#CONFIG_IEEE80211BE=y + # Wireless Network Management (IEEE Std 802.11v-2011) # Note: This is experimental and not complete implementation. #CONFIG_WNM=y diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index d570cfe9..b6dbc98a 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1148,6 +1148,7 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } + wpa_s->dpp_pkex_wait_auth_req = false; wpa_s->dpp_gas_client = 0; wpa_s->dpp_gas_server = 0; wpa_s->dpp_auth_ok_on_ack = 0; @@ -1661,6 +1662,21 @@ static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx) #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 +static void wpas_dpp_build_new_key(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_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + wpas_dpp_start_gas_client(wpa_s); +} +#endif /* CONFIG_DPP3 */ + + static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, @@ -1714,6 +1730,14 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, return; } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, wpas_dpp_build_new_key, wpa_s, + NULL); + return; + } +#endif /* CONFIG_DPP3 */ if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; @@ -2748,14 +2772,8 @@ static int wpas_dpp_pkex_done(void *ctx, void *conn, #endif /* CONFIG_DPP2 */ -enum wpas_dpp_pkex_ver { - PKEX_VER_AUTO, - PKEX_VER_ONLY_1, - PKEX_VER_ONLY_2, -}; - static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s, - enum wpas_dpp_pkex_ver ver, + enum dpp_pkex_ver ver, const struct hostapd_ip_addr *ipaddr, int tcp_port) { @@ -2908,6 +2926,17 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR, MAC2STR(src)); + if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only"); + return; + } + if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only"); + return; + } + /* TODO: Support multiple PKEX codes by iterating over all the enabled * values here */ @@ -2935,6 +2964,7 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } + wpa_s->dpp_pkex_wait_auth_req = false; msg = wpa_s->dpp_pkex->exchange_resp; wait_time = wpa_s->max_remain_on_chan; if (wait_time > 2000) @@ -3051,6 +3081,7 @@ wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src, wpabuf_free(msg); wpas_dpp_pkex_finish(wpa_s, src, freq); + wpa_s->dpp_pkex_wait_auth_req = true; } @@ -3332,11 +3363,13 @@ wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, return NULL; } + auth->conf_resp = resp; if (!resp) { wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); wpas_notify_dpp_configuration_failure(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; } - auth->conf_resp = resp; return resp; } @@ -3367,6 +3400,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key && ok) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + wpabuf_free(resp); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", ok); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); @@ -3493,6 +3534,8 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, wpa_printf(MSG_DEBUG, "DPP: Starting network introduction protocol to derive PMKSA for " MACSTR, MAC2STR(bss->bssid)); + if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state); len = 5 + 4 + os_strlen(ssid->dpp_connector); #ifdef CONFIG_DPP2 @@ -3614,6 +3657,11 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) { struct dpp_bootstrap_info *own_bi; const char *pos, *end; +#ifdef CONFIG_DPP3 + enum dpp_pkex_ver ver = PKEX_VER_AUTO; +#else /* CONFIG_DPP3 */ + enum dpp_pkex_ver ver = PKEX_VER_ONLY_1; +#endif /* CONFIG_DPP3 */ int tcp_port = DPP_TCP_PORT; struct hostapd_ip_addr *ipaddr = NULL; #ifdef CONFIG_DPP2 @@ -3679,27 +3727,22 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) if (!wpa_s->dpp_pkex_code) return -1; + pos = os_strstr(cmd, " ver="); + if (pos) { + int v; + + pos += 5; + v = atoi(pos); + if (v == 1) + ver = PKEX_VER_ONLY_1; + else if (v == 2) + ver = PKEX_VER_ONLY_2; + else + return -1; + } + wpa_s->dpp_pkex_ver = ver; + if (os_strstr(cmd, " init=1")) { -#ifdef CONFIG_DPP3 - enum wpas_dpp_pkex_ver ver = PKEX_VER_AUTO; -#else /* CONFIG_DPP3 */ - enum wpas_dpp_pkex_ver ver = PKEX_VER_ONLY_1; -#endif /* CONFIG_DPP3 */ - - pos = os_strstr(cmd, " ver="); - if (pos) { - int v; - - pos += 5; - v = atoi(pos); - if (v == 1) - ver = PKEX_VER_ONLY_1; - else if (v == 2) - ver = PKEX_VER_ONLY_2; - else - return -1; - } - if (wpas_dpp_pkex_init(wpa_s, ver, ipaddr, tcp_port) < 0) return -1; } else { @@ -3751,12 +3794,13 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id) void wpas_dpp_stop(struct wpa_supplicant *wpa_s) { - if (wpa_s->dpp_auth || wpa_s->dpp_pkex) + if (wpa_s->dpp_auth || wpa_s->dpp_pkex || wpa_s->dpp_pkex_wait_auth_req) offchannel_send_action_done(wpa_s); dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; dpp_pkex_free(wpa_s->dpp_pkex); wpa_s->dpp_pkex = NULL; + wpa_s->dpp_pkex_wait_auth_req = false; if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0) gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token); } @@ -3822,6 +3866,9 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) dpp_free_reconfig_id(wpa_s->dpp_reconfig_id); wpa_s->dpp_reconfig_id = NULL; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(wpas_dpp_build_new_key, wpa_s, NULL); +#endif /* CONFIG_DPP3 */ offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); wpas_dpp_stop(wpa_s); @@ -4236,6 +4283,7 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd) wpas_dpp_chirp_stop(wpa_s); wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_netrole = DPP_NETROLE_STA; wpa_s->dpp_qr_mutual = 0; wpa_s->dpp_chirp_bi = bi; wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi); @@ -4320,6 +4368,7 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd) } wpas_dpp_chirp_stop(wpa_s); wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_netrole = DPP_NETROLE_STA; wpa_s->dpp_qr_mutual = 0; wpa_s->dpp_reconfig_ssid = ssid; wpa_s->dpp_reconfig_ssid_id = ssid->id; diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index e256ac50..f8068957 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -15,6 +15,7 @@ #include "common.h" #include "utils/ext_password.h" #include "common/version.h" +#include "crypto/crypto.h" #include "crypto/tls.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" @@ -732,16 +733,27 @@ static char *eap_type_text(u8 type) case EAP_TYPE_IDENTITY: return "Identity"; case EAP_TYPE_NOTIFICATION: return "Notification"; case EAP_TYPE_NAK: return "Nak"; - case EAP_TYPE_TLS: return "TLS"; - case EAP_TYPE_TTLS: return "TTLS"; - case EAP_TYPE_PEAP: return "PEAP"; - case EAP_TYPE_SIM: return "SIM"; - case EAP_TYPE_GTC: return "GTC"; + case EAP_TYPE_MD5: return "MD5"; case EAP_TYPE_OTP: return "OTP"; + case EAP_TYPE_GTC: return "GTC"; + case EAP_TYPE_TLS: return "TLS"; + case EAP_TYPE_LEAP: return "LEAP"; + case EAP_TYPE_SIM: return "SIM"; + case EAP_TYPE_TTLS: return "TTLS"; + case EAP_TYPE_AKA: return "AKA"; + case EAP_TYPE_PEAP: return "PEAP"; + case EAP_TYPE_MSCHAPV2: return "MSCHAPv2"; case EAP_TYPE_FAST: return "FAST"; - case EAP_TYPE_SAKE: return "SAKE"; + case EAP_TYPE_PAX: return "PAX"; case EAP_TYPE_PSK: return "PSK"; + case EAP_TYPE_SAKE: return "SAKE"; + case EAP_TYPE_IKEV2: return "IKEv2"; + case EAP_TYPE_AKA_PRIME: return "AKA-PRIME"; + case EAP_TYPE_GPSK: return "GPSK"; + case EAP_TYPE_PWD: return "PWD"; + case EAP_TYPE_EKE: return "EKE"; + case EAP_TYPE_TEAP: return "TEAP"; default: return "Unknown"; } } @@ -761,20 +773,20 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) msg = e->last_recv_radius; eap = radius_msg_get_eap(msg); - if (eap == NULL) { - /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: + if (!eap) { + /* RFC 3579, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ - wpa_printf(MSG_DEBUG, "could not extract " - "EAP-Message from RADIUS message"); + wpa_printf(MSG_DEBUG, + "could not extract EAP-Message from RADIUS message"); wpabuf_free(e->last_eap_radius); e->last_eap_radius = NULL; return; } if (wpabuf_len(eap) < sizeof(*hdr)) { - wpa_printf(MSG_DEBUG, "too short EAP packet " - "received from authentication server"); + wpa_printf(MSG_DEBUG, + "too short EAP packet received from authentication server"); wpabuf_free(eap); return; } @@ -810,11 +822,11 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap); break; } - wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " - "id=%d len=%d) from RADIUS server: %s", - hdr->code, hdr->identifier, ntohs(hdr->length), buf); - - /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ + buf[sizeof(buf) - 1] = '\0'; + wpa_printf(MSG_DEBUG, + "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s", + hdr->code, hdr->identifier, be_to_host16(hdr->length), + buf); wpabuf_free(e->last_eap_radius); e->last_eap_radius = eap; @@ -847,7 +859,7 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e, keys = radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len); - if (keys && keys->send == NULL && keys->recv == NULL) { + if (keys && !keys->send && !keys->recv) { os_free(keys); keys = radius_msg_get_cisco_keys(msg, req, shared_secret, shared_secret_len); @@ -908,20 +920,19 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 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\n"); + 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)) { - printf("Incoming RADIUS packet did not have correct " - "Message-Authenticator - dropped\n"); - return RADIUS_RX_UNKNOWN; + wpa_printf(MSG_INFO, + "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); + return RADIUS_RX_INVALID_AUTHENTICATOR; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT && hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { - printf("Unknown RADIUS message code\n"); + wpa_printf(MSG_INFO, "Unknown RADIUS message code"); return RADIUS_RX_UNKNOWN; } @@ -1549,6 +1560,7 @@ int main(int argc, char *argv[]) else printf("SUCCESS\n"); + crypto_unload(); os_program_deinit(); return ret; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 35467ce9..170cec78 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -149,19 +149,22 @@ static struct wpa_bss * wpa_supplicant_get_new_bss( } -static void wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s) +static struct wpa_bss * +wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s, const u8 *bssid) { - struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid); + struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid); if (!bss) { wpa_supplicant_update_scan_results(wpa_s); /* Get the BSS from the new scan results */ - bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid); + bss = wpa_supplicant_get_new_bss(wpa_s, bssid); } if (bss) wpa_s->current_bss = bss; + + return bss; } @@ -173,7 +176,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) int res; if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) { - wpa_supplicant_update_current_bss(wpa_s); + wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); if (wpa_s->current_ssid->ssid_len == 0) return 0; /* current profile still in use */ @@ -250,7 +253,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; - wpa_supplicant_update_current_bss(wpa_s); + wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); wpa_supplicant_initiate_eapol(wpa_s); @@ -567,6 +570,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WEP int wep_ok; #endif /* CONFIG_WEP */ + bool is_6ghz_bss = is_6ghz_freq(bss->freq); ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) @@ -581,6 +585,13 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WEP */ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (is_6ghz_bss && !rsn_ie) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - 6 GHz BSS without RSNE"); + return 0; + } + while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) { proto_match++; @@ -595,6 +606,16 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, if (!ie.has_group) ie.group_cipher = wpa_default_rsn_cipher(bss->freq); + if (is_6ghz_bss) { + /* WEP and TKIP are not allowed on 6 GHz */ + ie.pairwise_cipher &= ~(WPA_CIPHER_WEP40 | + WPA_CIPHER_WEP104 | + WPA_CIPHER_TKIP); + ie.group_cipher &= ~(WPA_CIPHER_WEP40 | + WPA_CIPHER_WEP104 | + WPA_CIPHER_TKIP); + } + #ifdef CONFIG_WEP if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) @@ -636,6 +657,21 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, break; } + if (is_6ghz_bss) { + /* MFPC must be supported on 6 GHz */ + if (!(ie.capabilities & WPA_CAPABILITY_MFPC)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSNE - 6 GHz without MFPC"); + break; + } + + /* WPA PSK is not allowed on the 6 GHz band */ + ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + } + if (!(ie.key_mgmt & ssid->key_mgmt)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, @@ -666,6 +702,13 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 1; } + if (is_6ghz_bss) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - 6 GHz BSS without matching RSNE"); + return 0; + } + 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) @@ -1317,7 +1360,10 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, } #ifdef CONFIG_SAE - if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) && + /* When using SAE Password Identifier and when operationg on the 6 GHz + * band, only H2E is allowed. */ + if ((wpa_s->conf->sae_pwe == 1 || is_6ghz_freq(bss->freq) || + ssid->sae_password_id) && wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) && #ifdef CONFIG_DRIVER_NL80211_BRCM !(wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) && @@ -1412,7 +1458,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, if (wpa_s->ignore_assoc_disallow) goto skip_assoc_disallow; #endif /* CONFIG_TESTING_OPTIONS */ - assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW); + assoc_disallow = wpas_mbo_check_assoc_disallow(bss); if (assoc_disallow && assoc_disallow[1] >= 1) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, @@ -2961,6 +3007,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, BAND_2_4_GHZ); wpa_s->connection_he = req_elems.he_capabilities && resp_elems.he_capabilities; + wpa_s->connection_eht = req_elems.eht_capabilities && + resp_elems.eht_capabilities; int max_nss_rx_req = get_max_nss_capability(&req_elems, 1); int max_nss_rx_resp = get_max_nss_capability(&resp_elems, 1); @@ -3394,6 +3442,26 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */ ft_completed = wpa_ft_is_completed(wpa_s->wpa); + + if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { + wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID"); + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + return; + } + + if (ft_completed && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION)) { + wpa_msg(wpa_s, MSG_INFO, "Attempt to roam to " MACSTR, + MAC2STR(bssid)); + if (!wpa_supplicant_update_current_bss(wpa_s, bssid)) { + wpa_printf(MSG_ERROR, + "Can't find target AP's information!"); + return; + } + wpa_supplicant_assoc_update_ie(wpa_s); + } + if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) return; /* @@ -3404,13 +3472,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (!ft_completed) ft_completed = wpa_fils_is_completed(wpa_s->wpa); - if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { - wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID"); - wpa_supplicant_deauthenticate( - wpa_s, WLAN_REASON_DEAUTH_LEAVING); - return; - } - #if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA) /* For driver based roaming, insert PSK during the initial association */ if (is_zero_ether_addr(wpa_s->bssid) && diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index ca380b94..9a459c2f 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1065,6 +1065,12 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, goto fail; } + if (cred->imsi_privacy_key && cred->imsi_privacy_key[0]) { + if (wpa_config_set_quoted(ssid, "imsi_privacy_key", + cred->imsi_privacy_key) < 0) + goto fail; + } + wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); if (!only_add) diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c index 51a8a029..9229eb51 100644 --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -12,6 +12,7 @@ #endif /* __linux__ */ #include "common.h" +#include "crypto/crypto.h" #include "fst/fst.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -403,6 +404,7 @@ out: #endif /* CONFIG_MATCH_IFACE */ os_free(params.pid_file); + crypto_unload(); os_program_deinit(); return exitcode; diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c index 8ac73ef1..31d0fceb 100644 --- a/wpa_supplicant/mbo.c +++ b/wpa_supplicant/mbo.c @@ -65,14 +65,18 @@ const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, } -const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) +static const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, + enum mbo_attr_id attr, bool beacon) { const u8 *mbo, *end; if (!bss) return NULL; - mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); + if (beacon) + mbo = wpa_bss_get_vendor_ie_beacon(bss, MBO_IE_VENDOR_TYPE); + else + mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); if (!mbo) return NULL; @@ -83,6 +87,19 @@ const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) } +const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss) +{ + const u8 *assoc_disallow; + + assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW, + bss->beacon_newer); + if (assoc_disallow && assoc_disallow[1] >= 1) + return assoc_disallow; + + return NULL; +} + + void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { @@ -92,8 +109,8 @@ void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 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); + mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND, false); + oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND, false); if (!mbo && !oce) return; if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON)) diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c index d6b8a1ad..b67396d5 100644 --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c @@ -225,12 +225,13 @@ static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s) ifmsh->conf->ieee80211n, ifmsh->conf->ieee80211ac, ifmsh->conf->ieee80211ax, + false, ifmsh->conf->secondary_channel, hostapd_get_oper_chwidth(ifmsh->conf), hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf), hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf), ifmsh->conf->vht_capab, - he_capab)) { + he_capab, NULL)) { wpa_printf(MSG_ERROR, "Error updating mesh frequency params"); wpa_supplicant_mesh_deinit(wpa_s, true); return -1; diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 4c305186..1442353b 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -420,6 +420,10 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s, { if (wpa_s->next_ssid == ssid) wpa_s->next_ssid = NULL; + if (wpa_s->last_ssid == ssid) + wpa_s->last_ssid = NULL; + if (wpa_s->current_ssid == ssid) + wpa_s->current_ssid = NULL; if (wpa_s->wpa) wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s && diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index f1d033b3..c8f2e5ca 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -8899,7 +8899,7 @@ static void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s, hapd->conf->ssid.wpa_psk = psk->next; rem = psk; psk = psk->next; - os_free(rem); + bin_clear_free(rem, sizeof(*rem)); } else { prev = psk; psk = psk->next; diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index baf4c264..dc21b6a3 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -1000,6 +1000,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, struct wpa_ssid *ssid = NULL; struct wpabuf *frame; int ret; + bool derive_kdk; /* TODO: Currently support only ECC groups */ if (!dragonfly_suitable_group(group, 1)) { @@ -1079,9 +1080,14 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, pasn->group = group; pasn->freq = freq; - if (wpa_s->conf->force_kdk_derivation || - (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF && - ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) + derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) && + ieee802_11_rsnx_capab(beacon_rsnxe, + WLAN_RSNX_CAPAB_SECURE_LTF); +#ifdef CONFIG_TESTING_OPTIONS + if (!derive_kdk) + derive_kdk = wpa_s->conf->force_kdk_derivation; +#endif /* CONFIG_TESTING_OPTIONS */ + if (derive_kdk) pasn->kdk_len = WPA_KDK_MAX_LEN; else pasn->kdk_len = 0; diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index 31b55325..3ae99da0 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -13,6 +13,7 @@ #include #include "common.h" +#include "crypto/crypto.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "eloop.h" @@ -365,6 +366,7 @@ int main(int argc, char *argv[]) eloop_destroy(); + crypto_unload(); os_program_deinit(); return ret; diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c index cf107eba..4457b6c3 100644 --- a/wpa_supplicant/rrm.c +++ b/wpa_supplicant/rrm.c @@ -501,7 +501,7 @@ static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels, static int * wpas_add_channels(const struct oper_class_map *op, - struct hostapd_hw_modes *mode, int active, + struct hostapd_hw_modes *mode, const u8 *channels, const u8 size) { int *freqs, *next_freq; @@ -532,7 +532,7 @@ static int * wpas_add_channels(const struct oper_class_map *op, enum chan_allowed res = verify_channel(mode, op->op_class, chan, op->bw); - if (res == NOT_ALLOWED || (res == NO_IR && active)) + if (res == NOT_ALLOWED) continue; if (wpas_add_channel(op->op_class, chan, num_primary_channels, @@ -554,7 +554,7 @@ static int * wpas_add_channels(const struct oper_class_map *op, static int * wpas_op_class_freqs(const struct oper_class_map *op, - struct hostapd_hw_modes *mode, int active) + struct hostapd_hw_modes *mode) { u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 }; u8 channels_160mhz_5ghz[] = { 50, 114, 163 }; @@ -581,11 +581,11 @@ static int * wpas_op_class_freqs(const struct oper_class_map *op, ARRAY_SIZE(channels_160mhz_5ghz); } - return wpas_add_channels(op, mode, active, channels, num_chan); + return wpas_add_channels(op, mode, channels, num_chan); } -static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, +static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, const char *country, const u8 *subelems, size_t len) { @@ -633,7 +633,7 @@ static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, * by a corresponding AP Channel Report element as specified in * IEEE Std 802.11-2016, 11.11.9.1. */ - new_freqs = wpas_add_channels(op, mode, active, pos, left); + new_freqs = wpas_add_channels(op, mode, pos, left); if (new_freqs) int_array_concat(&freqs, new_freqs); @@ -648,7 +648,7 @@ out: static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, - u8 op_class, u8 chan, int active, + u8 op_class, u8 chan, const u8 *subelems, size_t len) { int *freqs = NULL, *ext_freqs = NULL; @@ -678,7 +678,7 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, switch (chan) { case 0: - freqs = wpas_op_class_freqs(op, mode, active); + freqs = wpas_op_class_freqs(op, mode); if (!freqs) return NULL; break; @@ -686,14 +686,13 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, /* freqs will be added from AP channel subelements */ break; default: - freqs = wpas_add_channels(op, mode, active, &chan, 1); + freqs = wpas_add_channels(op, mode, &chan, 1); if (!freqs) return NULL; break; } - ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems, - len); + ext_freqs = wpas_channel_report_freqs(wpa_s, country, subelems, len); if (ext_freqs) { int_array_concat(&freqs, ext_freqs); os_free(ext_freqs); @@ -1220,10 +1219,9 @@ wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s, goto out; } - params->freqs = wpas_beacon_request_freqs( - wpa_s, req->oper_class, req->channel, - req->mode == BEACON_REPORT_MODE_ACTIVE, - req->variable, len - sizeof(*req)); + params->freqs = wpas_beacon_request_freqs(wpa_s, req->oper_class, + req->channel, req->variable, + len - sizeof(*req)); if (!params->freqs) { wpa_printf(MSG_DEBUG, "Beacon request: No valid channels"); reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index dde2f444..042b24e1 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -2194,20 +2194,33 @@ static void dump_scan_res(struct wpa_scan_results *scan_res) for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *r = scan_res->res[i]; u8 *pos; + const u8 *ssid_ie, *ssid = NULL; + size_t ssid_len = 0; + + ssid_ie = wpa_scan_get_ie(r, WLAN_EID_SSID); + if (ssid_ie) { + ssid = ssid_ie + 2; + ssid_len = ssid_ie[1]; + } + if (r->flags & WPA_SCAN_LEVEL_DBM) { int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID); - wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " - "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u", - MAC2STR(r->bssid), r->freq, r->qual, + wpa_printf(MSG_EXCESSIVE, MACSTR + " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u", + MAC2STR(r->bssid), + wpa_ssid_txt(ssid, ssid_len), + r->freq, r->qual, r->noise, noise_valid ? "" : "~", r->level, r->snr, r->snr >= GREAT_SNR ? "*" : "", r->flags, r->age, r->est_throughput); } else { - wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " - "noise=%d level=%d flags=0x%x age=%u est=%u", - MAC2STR(r->bssid), r->freq, r->qual, + wpa_printf(MSG_EXCESSIVE, MACSTR + " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u", + MAC2STR(r->bssid), + wpa_ssid_txt(ssid, ssid_len), + r->freq, r->qual, r->noise, r->level, r->flags, r->age, r->est_throughput); } diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 0b02f751..cc55fa62 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1366,7 +1366,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, " auth_type=%u auth_transaction=%u status_code=%u", MAC2STR(bssid), WLAN_AUTH_SAE, auth_transaction, status_code); - return -1; + return -2; } if (auth_transaction == 1) { @@ -1517,7 +1517,10 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, if (res < 0) { /* Notify failure to the driver */ sme_send_external_auth_status( - wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE); + wpa_s, + res == -2 ? + le_to_host16(header->u.auth.status_code) : + WLAN_STATUS_UNSPECIFIED_FAILURE); return; } if (res != 1) diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 033589f7..0e2315d2 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1418,11 +1418,11 @@ static const char *network_fields[] = { #ifdef IEEE8021X_EAPOL "eap", "identity", "anonymous_identity", "password", "ca_cert", "ca_path", "client_cert", "private_key", "private_key_passwd", - "dh_file", "subject_match", "altsubject_match", + "subject_match", "altsubject_match", "check_cert_subject", "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2", "client_cert2", "private_key2", "private_key2_passwd", - "dh_file2", "subject_match2", "altsubject_match2", + "subject_match2", "altsubject_match2", "check_cert_subject2", "domain_suffix_match2", "domain_match2", "phase1", "phase2", "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id", @@ -2046,6 +2046,20 @@ static int wpa_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); } + +static int wpa_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv); +} + + +static int wpa_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv); +} + #endif /* CONFIG_AP */ @@ -2894,6 +2908,31 @@ static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv #endif /* CONFIG_WNM */ +#ifdef CONFIG_WNM_AP + +static int wpa_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DISASSOC_IMMINENT", 2, argc, argv); +} + + +static int wpa_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ESS_DISASSOC", 3, argc, argv); +} + + +static int wpa_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "BSS_TM_REQ", 1, argc, argv); +} + +#endif /* CONFIG_WNM_AP */ + + static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) @@ -3599,6 +3638,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "update_beacon", wpa_cli_cmd_update_beacon, NULL, cli_cmd_flag_none, "= update Beacon frame contents"}, + { "accept_acl", wpa_cli_cmd_accept_macacl, NULL, cli_cmd_flag_none, + "=Add/Delete/Show/Clear allow MAC ACL" }, + { "deny_acl", wpa_cli_cmd_deny_macacl, NULL, cli_cmd_flag_none, + "=Add/Delete/Show/Clear deny MAC ACL" }, #endif /* CONFIG_AP */ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, "= notification of suspend/hibernate" }, @@ -3845,6 +3888,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { " [neighbor=,,,,[,]" " = Send BSS Transition Management Query" }, #endif /* CONFIG_WNM */ +#ifdef CONFIG_WNM_AP + { "disassoc_imminent", wpa_cli_cmd_disassoc_imminent, NULL, cli_cmd_flag_none, + "= send Disassociation Imminent notification" }, + { "ess_disassoc", wpa_cli_cmd_ess_disassoc, NULL, cli_cmd_flag_none, + "= send ESS Dissassociation Imminent notification" }, + { "bss_tm_req", wpa_cli_cmd_bss_tm_req, NULL, cli_cmd_flag_none, + "= send BSS Transition Management Request" }, +#endif /* CONFIG_WNM_AP */ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, " = Sent unprocessed command" }, { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none, diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c index 538997e6..d9c07e67 100644 --- a/wpa_supplicant/wpa_passphrase.c +++ b/wpa_supplicant/wpa_passphrase.c @@ -58,7 +58,11 @@ int main(int argc, char *argv[]) return 1; } - pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32); + if (pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32) + != 0) { + fprintf(stderr, "Error in pbkdf2_sha1()\n"); + return 1; + } printf("network={\n"); printf("\tssid=\"%s\"\n", ssid); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 99af85e0..24c8818f 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1715,6 +1715,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_s->oci_freq_override_ft_assoc); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC, wpa_s->oci_freq_override_fils_assoc); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX, + wpa_s->disable_eapol_g2_tx); #endif /* CONFIG_TESTING_OPTIONS */ /* Extended Key ID is only supported in infrastructure BSS so far */ @@ -1786,9 +1788,15 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase && !sae_only) { u8 psk[PMK_LEN]; - pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len, - 4096, psk, PMK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", + + if (pbkdf2_sha1(ssid->passphrase, bss->ssid, + bss->ssid_len, + 4096, psk, PMK_LEN) != 0) { + wpa_msg(wpa_s, MSG_WARNING, + "Error in pbkdf2_sha1()"); + return -1; + } + wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL); psk_set = 1; @@ -1822,8 +1830,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #ifndef CONFIG_NO_PBKDF2 if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss) { - pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len, - 4096, psk, PMK_LEN); + if (pbkdf2_sha1(pw_str, bss->ssid, + bss->ssid_len, + 4096, psk, PMK_LEN) != 0) { + wpa_msg(wpa_s, MSG_WARNING, + "Error in pbkdf2_sha1()"); + ext_password_free(pw); + return -1; + } os_memset(pw_str, 0, sizeof(pw_str)); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " "external passphrase)", @@ -2247,6 +2261,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, else rand_style = ssid->mac_addr; + wpa_s->eapol_failed = 0; wpa_s->multi_ap_ie = 0; wmm_ac_clear_saved_tspecs(wpa_s); wpa_s->reassoc_same_bss = 0; @@ -2779,9 +2794,11 @@ skip_to_6ghz: freq->channel, ssid->enable_edmg, ssid->edmg_channel, freq->ht_enabled, vht_freq.vht_enabled, freq->he_enabled, + false, freq->sec_channel_offset, chwidth, seg0, seg1, vht_caps, - &mode->he_capab[ieee80211_mode]) != 0) + &mode->he_capab[ieee80211_mode], + NULL) != 0) return; *freq = vht_freq; @@ -4280,7 +4297,7 @@ struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s) */ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) { - struct wpa_ssid *ssid; + struct wpa_ssid *ssid, *prev = wpa_s->current_ssid; int was_disabled; ssid = wpa_config_get_network(wpa_s->conf, id); @@ -4288,10 +4305,7 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) return -1; wpas_notify_network_removed(wpa_s, ssid); - if (wpa_s->last_ssid == ssid) - wpa_s->last_ssid = NULL; - - if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) { + if (ssid == prev || !prev) { #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ @@ -4302,7 +4316,7 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) eapol_sm_invalidate_cached_session(wpa_s->eapol); } - if (ssid == wpa_s->current_ssid) { + if (ssid == prev) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); @@ -4365,8 +4379,6 @@ int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s) id = ssid->id; ssid = ssid->next; - if (wpa_s->last_ssid == remove_ssid) - wpa_s->last_ssid = NULL; wpas_notify_network_removed(wpa_s, remove_ssid); wpa_config_remove_network(wpa_s->conf, id); } @@ -6747,6 +6759,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->drv_flags2 = capa.flags2; wpa_s->drv_enc = capa.enc; wpa_s->drv_rrm_flags = capa.rrm_flags; + wpa_s->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; wpa_s->probe_resp_offloads = capa.probe_resp_offloads; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 9376b03c..fd54fefb 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -1234,14 +1234,6 @@ fast_reauth=1 # to blob://. # private_key_passwd: Password for private key file (if left out, this will be # asked through control interface) -# dh_file: File path to DH/DSA parameters file (in PEM format) -# This is an optional configuration file for setting parameters for an -# ephemeral DH key exchange. In most cases, the default RSA -# authentication does not use this configuration. However, it is possible -# setup RSA to use ephemeral DH key exchange. In addition, ciphers with -# DSA keys always use ephemeral DH keys. This can be used to achieve -# forward secrecy. If the file is in DSA parameters format, it will be -# automatically converted into DH params. # subject_match: Substring to be matched against the subject of the # authentication server certificate. If this string is set, the server # certificate is only accepted if it contains this string in the subject. @@ -1378,6 +1370,11 @@ fast_reauth=1 # tls_suiteb=0 - do not apply Suite B 192-bit constraints on TLS (default) # tls_suiteb=1 - apply Suite B 192-bit constraints on TLS; this is used in # particular when using Suite B with RSA keys of >= 3K (3072) bits +# allow_unsafe_renegotiation=1 - allow connection with a TLS server that does +# not support safe renegotiation (RFC 5746); please note that this +# workaround should be only when having to authenticate with an old +# authentication server that cannot be updated to use secure TLS +# implementation. # # Following certificate/private key fields are used in inner Phase2 # authentication when using EAP-TTLS or EAP-PEAP. diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 1d2c3e24..3adb8190 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -14,6 +14,7 @@ #include "common/defs.h" #include "common/sae.h" #include "common/wpa_ctrl.h" +#include "common/dpp.h" #include "crypto/sha384.h" #include "eapol_supp/eapol_supp_sm.h" #include "wps/wps_defs.h" @@ -929,6 +930,7 @@ struct wpa_supplicant { u64 drv_flags2; unsigned int drv_enc; unsigned int drv_rrm_flags; + unsigned int drv_max_acl_mac_addrs; /* * A bitmap of supported protocols for probe response offload. See @@ -965,6 +967,7 @@ struct wpa_supplicant { struct os_reltime pending_eapol_rx_time; u8 pending_eapol_rx_src[ETH_ALEN]; unsigned int last_eapol_matches_bssid:1; + unsigned int eapol_failed:1; unsigned int eap_expected_failure:1; unsigned int reattach:1; /* reassociation to the same BSS requested */ unsigned int mac_addr_changed:1; @@ -976,6 +979,7 @@ struct wpa_supplicant { unsigned int connection_ht:1; unsigned int connection_vht:1; unsigned int connection_he:1; + unsigned int connection_eht:1; unsigned int connection_max_nss_rx:4; unsigned int connection_max_nss_tx:4; unsigned int connection_channel_bandwidth:5; @@ -1368,6 +1372,7 @@ struct wpa_supplicant { unsigned int oci_freq_override_fils_assoc; unsigned int oci_freq_override_wnm_sleep; int force_hunting_and_pecking_pwe; + unsigned int disable_eapol_g2_tx; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -1483,6 +1488,7 @@ struct wpa_supplicant { struct dpp_bootstrap_info *dpp_pkex_bi; char *dpp_pkex_code; char *dpp_pkex_identifier; + enum dpp_pkex_ver dpp_pkex_ver; char *dpp_pkex_auth_cmd; char *dpp_configurator_params; struct os_reltime dpp_last_init; @@ -1495,6 +1501,7 @@ struct wpa_supplicant { u8 dpp_last_ssid[SSID_MAX_LEN]; size_t dpp_last_ssid_len; bool dpp_conf_backup_received; + bool dpp_pkex_wait_auth_req; #ifdef CONFIG_DPP2 struct dpp_pfs *dpp_pfs; int dpp_pfs_fallback; @@ -1707,7 +1714,7 @@ void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s); int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len, 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); +const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss); 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, diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 85028f00..c2bd45f2 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -298,13 +298,21 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, EAPOL_SUPP_RESULT_EXPECTED_FAILURE; if (result != EAPOL_SUPP_RESULT_SUCCESS) { + int timeout = 2; /* * Make sure we do not get stuck here waiting for long EAPOL * timeout if the AP does not disconnect in case of * authentication failure. */ - wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); + if (wpa_s->eapol_failed) { + wpa_printf(MSG_DEBUG, + "EAPOL authentication failed again and AP did not disconnect us"); + timeout = 0; + } + wpa_s->eapol_failed = 1; + wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0); } else { + wpa_s->eapol_failed = 0; ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src); } diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c index defd0f2f..c3ef93bf 100644 --- a/wpa_supplicant/wpas_kay.c +++ b/wpa_supplicant/wpas_kay.c @@ -103,7 +103,6 @@ static unsigned int conf_offset_val(enum confidentiality_offset co) switch (co) { case CONFIDENTIALITY_OFFSET_30: return 30; - break; case CONFIDENTIALITY_OFFSET_50: return 50; default: @@ -241,8 +240,8 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect, ssid->macsec_replay_window, ssid->macsec_port, - ssid->mka_priority, wpa_s->ifname, - wpa_s->own_addr); + ssid->mka_priority, ssid->macsec_csindex, + wpa_s->ifname, wpa_s->own_addr); /* ieee802_1x_kay_init() frees kay_ctx on failure */ if (res == NULL) return -1; diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 1ba360e8..7428f020 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -356,8 +356,6 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, /* Remove the duplicated older network entry. */ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpas_notify_network_removed(wpa_s, ssid); - if (wpa_s->current_ssid == ssid) - wpa_s->current_ssid = NULL; wpa_config_remove_network(wpa_s->conf, ssid->id); } }