FILS does not use a MIC, as well as requires encrypted data on GTK 2/2.
This updates eapol_create_gtk_2_of_2 to pass in extra data to
eapol_create_common, which will reserve room for this encrypted data.
Extra data is only reserved if mic_len == 0.
FILS does not use a MIC in EAPoL frames and also requires encrypted
data on all EAPoL frames. In the common builder the mic_len is now
checked and the flags are set appropriately.
FILS authentication does away with the MIC, so checking for key_mic
in the eapol key frame does not allow FILS to work. Now we pass in
the mic_len to eapol_verify_gtk_1_of_2, and if it is non-zero we can
check that the MIC is present in the frame.
FILS does not require an eapol_sm for authentication, but rekeys
are still performed using the 4-way handshake. Because of this
FILS needs to create a eapol_sm in a 'started' state, but without
calling eapol_start as this will initialize EAP and create handshake
timeouts.
This allows EAPoL to wait for any 4-way packets, and handle them
as rekeys.
ERP (EAP Reauthentication Protocol) allows a station to quickly
reauthenticate using keys from a previous EAP authentication.
This change both implements ERP as well as moves the key cache into
the ERP module.
ERP in its current form is here to only support FILS. ERP is likely not
widespread and there is no easy way to determine if an AP supports ERP
without trying it. Attempting ERP with a non-ERP enabled AP will actually
result in longer connection times since ERP must fail and then full EAP
is done afterwards. For this reason ERP was separated from EAP and a
separate ERP state machine must be created. As it stands now, ERP cannot
be used on its own, only with FILS.
Quick scan uses a set of frequencies associated with the
known networks. This allows to reduce the scan latency.
At this time, the frequency selection follows a very simple
logic by taking all known frequencies from the top 5 most
recently connected networks.
If connection isn't established after the quick scan attempt,
we fall back to the full periodic scan.
Instead of handling NEW_WIPHY events and WIHPY_DUMP events in a similar
fashion, split up the paths to optimize iwd startup time. There's
fundamentally no reason to wait a second (and eat up file-descriptor
resources for timers unnecessarily) when we can simply start an
interface dump right after the wiphy dump.
In case a new wiphy is added in the middle of a wiphy dump, we will
likely get a new wiphy event anyway, in which case a setup_timeout will
be created and we will ignore this phy during the interface dump
processing.
This also optimizes the case of iwd being re-started, in which case
there are no interfaces present.
Separate out the two types of NEW_WIPHY handlers into separate paths and
factor out the common code into a utility function.
Dumps of CMD_NEW_WIPHY can be split up over several messages, while
CMD_NEW_WIPHY events (generated when a new card is plugged in) are
stuffed into a single message.
This also prepares ground for follow-on commits where we will handle the
two types of events differently.
src/netdev.c:netdev_create_from_genl() Skipping duplicate netdev wlp2s0[3]
Aborting (signal 11) [/home/denkenz/iwd/src/iwd]
++++++++ backtrace ++++++++
#0 0x7fc4c7a4e930 in /lib64/libc.so.6
#1 0x40ea13 in netdev_getlink_cb() at src/netdev.c:4654
#2 0x468cab in process_message() at ell/netlink.c:183
#3 0x4690a3 in can_read_data() at ell/netlink.c:289
#4 0x46681d in io_callback() at ell/io.c:126
#5 0x4651cd in l_main_iterate() at ell/main.c:473
#6 0x46530e in l_main_run() at ell/main.c:516
#7 0x465626 in l_main_run_with_signal() at ell/main.c:642
#8 0x403df8 in main() at src/main.c:513
#9 0x7fc4c7a39bde in /lib64/libc.so.6
Mirror netdev.c white/blacklist logic. If either or both the whitelist
and the blacklist are given also fall back to not touching the existing
interface setup on the wiphy.
If we get an error during DEL_INTERFACE or NEW_INTERFACE we may be
dealing with a driver that doesn't implement virtual interfaces or
doesn't implement deleting the default interface. In this case fall
back to using the first usable interface that we've detected on this
wiphy.
There's at least one full-mac driver that doesn't implement the cfg80211
.del_virtual_intf and .add_virtual_intf methods and at least one that
only allows P2P interfaces to be manipulated. mac80211 drivers seem to
at least implement those methods but I didn't check to see if there are
driver where they'd eventually return EOPNOTSUPP.
This is probably the trickiest part in this patchset. I'm introducing a
new logic where instead of using the interfaces that we find present
when a wiphy is detected, which would normally be the one default
interface per wiphy but could be 0 or more than one, we create one
ourselves with the socket owner attribute and use exactly one for
Station, AP and Ad-Hoc modes. When IWD starts we delete all the
interfaces on existing wiphys that we're going to use (as determined by
the wiphy white/blacklists) or freshly hotplugged ones, and only then we
register the interface we're going to use meaning that the wiphy's
limits on the number of concurrent interfaces of each type should be at
0. Otherwise we'd be unlikely to be abe to create the station interface
as most adapters only allow one. After that we ignore any interfaces
that may be created by other processes as we have no use for multiple
station interfaces.
At this point manager.c only keeps local state for wiphys during
the interface setup although when we start adding P2P code we will be
creating and removing interfaces multiple times during the wiphy's
runtime and may need to track it here or in wiphy.c. We do not
specifically check the interface number limits received during the wiphy
dump, if we need to create any interfaces and we're over the driver's
maximum for that specific iftype we'll still attempt it and report error
if it fails.
I tested this and it seems to work with my laptop's intel card and some
USB hotplug adapters.
The latest refactoring ended up assuming that FT related elements would
be handled in netdev_associate_event. However, FullMac cards (that do
not generate netdev_associate_event) could still connect using FT AKMs
and perform the Initial mobility association. In such cases the FTE
element was required but ended up not being set into the handshake.
This caused the handshake to fail during PTK 1_of_4 processing.
Fix this by making sure that FTE + related info is set into the
handshake, albeit with a lower sanity checking level since the
elements have been processed by the firmware already.
Note that it is currently impossible for actual FTs to be performed on
FullMac cards, so the extra logic and sanity checking to handle these
can be skipped.
Add functionality to read and parse the known frequencies
from permanent storage on start of the service. On service
shutdown, we sync the known frequencies back to the permanent
storage.
Each known network (previously connected) will have a set
of known frequencies associated with it, e.g. a set of
frequencies from all BSSs observed. The list of known
frequencies is sorted with the most recently observed
frequency in the head.
Previously, the scan results were disregarded once the new
ones were available. To enable the scan scenarios where the
new scan results are delivered in parts, we introduce a
concept of aging BSSs and will remove them based on
retention time.
Add manager.c, a new file where the wiphy and interface creation/removal
will be handled and interface use policies will be implemented. Since
not all kernel-side nl80211 interfaces are tied to kernel-side netdevs,
netdev.c can't manage all of the interfaces that we will be using, so
the logic is being moved to a common place where all interfaces on a
wiphy will be managed according to the policy, device support for things
like P2P and user enabling/disabling/connecting with P2P which require
interfaces to be dynamically added and removed.
Add wiphy_create, wiphy_update_from_genl and wiphy_destroy that together
will let a new file command the wiphy creation, updates and deletion
with the same functionality the current config notification handler
implements in wiphy.c.
As mentioned in code comments the name is NUL-terminated so there's no
need to return the length path, which was ignored in some occasions
anyway. Consistently treat it as NUL-terminated but also validate.
Make netdev_create_from_genl public and change signature to return the
created netdev or NULL. Also add netdev_destroy that destroys and
unregisters the created netdevs. Both will be used to move the
whole interface management to a new file.
The handshake_state only holds a single AKM value. FILS depends on the AP
supporting EAP as well as FILS. The first time IWD connects, it will do a
full EAP auth. Subsequent connections (assuming FILS is supported) will use
FILS. But if the AP does not support FILS there is no reason to cache the
ERP keys.
This adds the supp_fils to the handshake_state. Now, station.c can set this
flag while building the handshake. This flag can later be checked when
caching the ERP keys.
This allows IWD to cache ERP keys after a full EAP run. Caching
allows IWD to quickly connect to the network later on using ERP or
FILS.
The cache will contain the EAP Identity, Session ID, EMSK, SSID and
optionally the ERP domain. For the time being, the cache entry
lifetimes are hard coded to 24 hours. Eventually the cache should
be written to disk to allow ERP/FILS to work after a reboot or
IWD restart.
mschaputil already had similar functionality, but ERP will need this
as well. These two functions will also handle identities with either
'@' or '\' to separate the user and domain.
Many operations performed during an error in load_settings were the same
as the ones performed when freeing the eap object. Add eap_free_common
to unify these.
EAP identites are recommended to follow RFC 4282 (The Network Access
Identifier). This RFC recommends a maximum NAI length of 253 octets.
It also mentions that RADIUS is only able to support NAIs of 253
octets.
Because of this, IWD should not allow EAP identities larger than 253
bytes. This change adds a check in eap_load_settings to verify the
identity does not exceed this limit.
The associate event is only important for OWE and FT. If neither of
these conditions (or FT initial association) are happening we do
not need to continue further processing the associate event.
802.11 mandates that IEs inside management frames are presented in a
given order. However, in the real world, many APs seem to ignore the
rules and send their IEs in seemingly arbitrary order, especially when
it comes to VENDOR tags. Change this function to no longer be strict in
enforcing the order.
Also, drop checking of rules specific to Probe Responses. These will
have to be handled separately (most likely by the AP module) since
802.11-2016, Section 11.1.4.3.5 essentially allows just about anything.
In netdev_associate_event the ignore_connect_event was getting set true,
but afterwards there were still potential failure paths. Now, once in
assoc_failed we explicitly set ignore_connect_event to false so the
the failure can be handled properly inside netdev_connect_event
The list of PSK/8021x AKM's in security_determine was getting long,
and difficult to keep under 80 characters. This moves them all into
two new macros, AKM_IS_PSK/AKM_IS_8021X.
It was assumed that the hunt-and-peck loop was guarenteed to find
a PWE. This was incorrect in terms of kernel support. If a system
does not have support for AF_ALG or runs out of file descriptors
the KDFs may fail. The loop continued to run if found == false,
which is also incorrect because we want to stop after 20 iterations
regarless of success.
This changes the loop to a for loop so it will always exit after
the set number of iterations.
CC src/scan.o
src/scan.c: In function ‘scan_bss_compute_rank’:
src/scan.c:1048:4: warning: this decimal constant is unsigned only in ISO C90
factor = factor * data_rate / 2340000000 +
The auto-connect state will now consist of the two phases:
STATION_STATE_AUTOCONNECT_QUICK and STATION_STATE_AUTOCONNECT_FULL.
The auto-connect will always start with STATION_STATE_AUTOCONNECT_QUICK
and then transition into STATION_STATE_AUTOCONNECT_FULL if no
connection has been established. During STATION_STATE_AUTOCONNECT_QUICK
phase we take advantage of the wireless scans with the limited number
of channels on which the known networks have been observed before.
This approach allows to shorten the time required for the network
sweeps, therefore decreases the connection latency if the connection
is possible. Thereafter, if no connection has been established after
the first phase we transition into STATION_STATE_AUTOCONNECT_FULL and
do the periodic scan just like we did before the split in
STATION_STATE_AUTOCONNECT state.
For simplicity 160Mhz and 80+80Mhz were grouped together when
parsing the VHT capabilities, but the 80+80 bits were left in
vht_widht_map. This could cause an overflow when getting the
width map.
wiphy_select_akm will now check if BIP is supported, and if MFPR is
set in the scan_bss before returning either SAE AKMs. This will allow
fallback to another PSK AKM (e.g. hybrid APs) if any of the requirements
are not met.
Replace existing uses of memset to clear secrets with explicit_bzero to
make sure it doesn't get optimized away. This has some side effects as
documented in gcc docs but is still recommended.
In eap_secret_info_free make sure we clear both strings in the case of
EAP_SECRET_REMOTE_USER_PASSWORD secrets.
Environments with several AP's, all at low signal strength may
want to lower the roaming RSSI threshold to prevent IWD from
roaming excessively. This adds an option 'roam_rssi_threshold',
which is still defaulted to -70.
Also printing keys with l_debug conditional on an environment variable
as someone wanting debug logs, or leaving debug on accidentally, does
not necessarily want the keys in the logs and in memory.
At some point the connect command builder was modified, and the
control port over NL80211 check was moved to inside if (is_rsn).
For WPS, no supplicant_ie was set, so CONTROL_PORT_OVER_NL80211
was never set into CMD_CONNECT. This caused IWD to expect WPS
frames over netlink, but the kernel was sending them over the
legacy route.
This commit hardens the iwd.service.in template file for systemd
services. The following is a short explanation for each added directive:
+PrivateTmp=true
If true, sets up a new file system namespace for the executed processes
and mounts private /tmp and /var/tmp directories inside it that is not
shared by processes outside of the namespace.
+NoNewPrivileges=true
If true, ensures that the service process and all its children can never
gain new privileges through execve() (e.g. via setuid or setgid bits, or
filesystem capabilities).
+PrivateDevices=true
If true, sets up a new /dev mount for the executed processes and only
adds API pseudo devices such as /dev/null, /dev/zero or /dev/random (as
well as the pseudo TTY subsystem) to it, but no physical devices such as
/dev/sda, system memory /dev/mem, system ports /dev/port and others.
+ProtectHome=yes
If true, the directories /home, /root and /run/user are made
inaccessible and empty for processes invoked by this unit.
+ProtectSystem=strict
If set to "strict" the entire file system hierarchy is mounted
read-only, except for the API file system subtrees /dev, /proc and /sys
(protect these directories using PrivateDevices=,
ProtectKernelTunables=, ProtectControlGroups=).
+ReadWritePaths=/var/lib/iwd/
Sets up a new file system namespace for executed processes. These
options may be used to limit access a process might have to the file
system hierarchy. Each setting takes a space-separated list of paths
relative to the host's root directory (i.e. the system running the
service manager). Note that if paths contain symlinks, they are resolved
relative to the root directory set with RootDirectory=/RootImage=.
Paths listed in ReadWritePaths= are accessible from within
the namespace with the same access modes as from outside of
it.
+ProtectControlGroups=yes
If true, the Linux Control Groups (cgroups(7)) hierarchies accessible
through /sys/fs/cgroup will be made read-only to all processes of the
unit.
+ProtectKernelModules=yes
If true, explicit module loading will be denied. This allows module
load and unload operations to be turned off on modular kernels.
For further explanation to all directives see `man systemd.directives`
Hostapd has now been updated to include the group number when rejecting
the connection with UNSUPP_FINITE_CYCLIC_GROUP. We still need the existing
len == 0 check because old hostapd versions will still behave this way.