Hostapd commit b6d3fd05e3 changed the PMKID derivation in accordance
with 802.11-2020 which then breaks PMKID validation in IWD. This
breaks the FT-8021x AKM in IWD if the AP uses this hostapd version
since the PMKID doesn't validate during EAPoL.
This updates the PMKID derivation to use the correct SHA hash for
this AKM and adds SHA1 based PMKID checking for interoperability
with older hostapd versions.
The PMKID derivation has gotten messy due to the spec
updating/clarifying the hash size for the FT-8021X AKM. This
has led to hostapd updating the derivation which leaves older
hostapd versions using SHA1 and newer versions using SHA256.
To support this the checksum type is being fed to
handshake_state_get_pmkid so the caller can decide what sha to
use. In addition handshake_state_pmkid_matches is being added
which uses get_pmkid() but handles sorting out the hash type
automatically.
This lets preauthentication use handshake_state_get_pmkid where
there is the potential that a new PMKID is derived and eapol
can use handshake_state_pmkid_matches which only derives the
PMKID to compare against the peers.
The existing API was limited to SHA1 or SHA256 and assumed a key
length of 32 bytes. Since other AKMs plan to be added update
this to take the checksum/length directly for better flexibility.
Like in ap.c, allow the event callback to mark the handshake state as
destroyed, without causing invalid accesses after the callback has
returned. In this case the crash was because try_handshake_complete
needed to access members of handshake_state after emitting the event,
as well as access the netdev, which also has been destroyed:
==257707== Invalid read of size 8
==257707== at 0x408C85: try_handshake_complete (netdev.c:1487)
==257707== by 0x408C85: try_handshake_complete (netdev.c:1480)
(...)
==257707== Address 0x4e187e8 is 856 bytes inside a block of size 872 free'd
==257707== at 0x484621F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==257707== by 0x437887: ap_stop_handshake (ap.c:151)
==257707== by 0x439793: ap_del_station (ap.c:316)
==257707== by 0x43EA92: ap_station_disconnect (ap.c:3411)
==257707== by 0x43EA92: ap_station_disconnect (ap.c:3399)
==257707== by 0x454276: p2p_group_event (p2p.c:1006)
==257707== by 0x439147: ap_event (ap.c:281)
==257707== by 0x4393AB: ap_new_rsna (ap.c:390)
==257707== by 0x4393AB: ap_handshake_event (ap.c:1010)
==257707== by 0x408C7F: try_handshake_complete (netdev.c:1485)
==257707== by 0x408C7F: try_handshake_complete (netdev.c:1480)
(...)
- Mostly problems with whitespace:
- Use of spaces instead of tabs
- Stray spaces before closing ')
- Missing spaces
- Missing 'void' from function declarations & definitions that
take no arguments.
- Wrong indentation level
Direct leak of 7 byte(s) in 1 object(s) allocated from:
#0 0x7fd748ad00f8 in __interceptor_malloc (/usr/lib/gcc/x86_64-pc-linux-gnu/9.4.0/libasan.so.5+0x10c0f8)
#1 0x688c21 in l_malloc ell/util.c:62
#2 0x4beec7 in handshake_state_set_vendor_ies src/handshake.c:324
#3 0x464e4e in station_handshake_setup src/station.c:1203
#4 0x472a2f in __station_connect_network src/station.c:2975
#5 0x473a30 in station_connect_network src/station.c:3078
#6 0x4ed728 in network_connect_8021x src/network.c:1497
Fixes: f24cfa481b ("handshake: Add setter for vendor IEs")
The procedure for setting extended key IDs is different from the
single PTK key. The key ID is toggled between 0 and 1 and the new
key is set as RX only, then set to RX/TX after message 4/4 goes
out.
Since netdev needs to set this new key before sending message 4,
eapol can include a built message which netdev will store if
required (i.e. using PAE).
ext_key_id_capable indicates the handshake has set the capability bit
in the RSN info. This will only be set if the AP also has the capability
set.
active_tk_index is the key index the AP chose in message 3. This is
now used for both legacy (always zero) and extended key IDs.
Add a utility for setting the OCI obtained from the hardware (prior to
handshake starting) as well as a utility to validate the OCI obtained
from the peer.
Calling handshake_state_setup_own_ciphers from within
handshate_state_set_authenticator_ie was misleading. In all cases the
supplicant chooses the AKM. This worked since our AP code only ever
advertises a single AKM, but would not work in the general case.
Similarly, the supplicant would choose which authentication type to use
by either sending the WPA1 or WPA2 IE (or OSEN). Thus the setting of
the related variables in handshake_state_set_authenticator_ie was also
incorrect. In iwd, the supplicant_ie would be set after the
authenticator_ie, so these settings would be overwritten in most cases.
Refactor these two setters so that the supplicant's chosen rsn_info
would be used to drive the handshake.
handshake_util_ap_ie_matches() is used to make sure that the RSN element
received from the Authenticator during handshake / association response
is the same as the one advertised in Beacon/Probe Response frames. This
utility tries to bitwise compare the element first, and only if that
fails, compares RSN members individually.
For FT, bitwise comparison will always fail since the PMKID has to be
included by the Authenticator in any RSN IEs included in Authenticate
& Association Response frames.
Perform the bitwise comparison as an optimization only during processing
of eapol message 3/4. Also keep the parsed rsn information for future
use and to possibly avoid re-parsing it during later checks.
Send and receive the FILS IP Address Assignment IEs during association.
As implemented this would work independently of FILS although the only
AP software handling this mechanism without FILS is likely IWD itself.
No support is added for handling the IP assignment information sent from
the server after the initial Association Request/Response frames, i.e.
the information is only used if it is received directly in the
Association Response without the "response pending" bit, otherwise the
DHCP client will be started.
Some connections, like Hotspot require additional IEs to be used during
the Association. These are now passed as 'extra_ies' when invoking
netdev_connect, however they are also needed during ReAssociation and FT
to such APs.
Additionally, it may be that Hotspot-enabled APs will start utilizing
FILS or SAE. In these cases the extra_ies need to be accounted for
somehow, either by making a copy in handshake_state, netdev, or the
auth_proto itself. Similarly, P2P which heavily uses vendor IEs can be
used over SAE in the future.
Since a copy of these IEs is needed, might as well store them in
handshake_state itself for easy book-keeping by network/station.
During processing of Connect events by netdev, some of these elements
might be updated even when already set. Instead of issuing
l_free/l_memdup each time, check and see whether the elements are
bitwise identical first.
This bug has been in here since OWE was written, but a similar bug also
existed in hostapd which allowed the PTK derivation to be identical.
In January 2020 hostapd fixed this bug, which now makes IWD incompatible
when using group 20 or 21.
This patch fixes the bug for IWD, so now OWE should be compatible with
recent hostapd version. This will break compatibility with old hostapd
versions which still have this bug.
Convert the handshake event callback type to use variable argument
list to allow for more flexibility in event-specific arguments
passed to the callbacks.
Note the uint16_t reason code is promoted to an int when using variable
arguments so va_arg(args, int) has to be used.
The handshake object had 4 setters for authenticator/supplicant IE.
Since the IE ultimately gets put into the same buffer, there really
only needs to be a single setter for authenticator/supplicant. The
handshake object can deal with parsing to decide what kind of IE it
is (WPA or RSN).
FILS-FT is a special case with respect to the PTK keys. The KCK getter
was updated to handle both FT-FILS AKMs, by returning the offset in
the PTK to the special KCK generated during FILS. A getter for the KCK
length was added, which handles the SHA384 variant. The PTK size was
also updated since FILS-FT can generate an additional 56 bytes of PTK
For FILS rekeys, we still derive the PTK using the 4-way handshake.
And for FILS-SHA384 we need the SHA384 KDF variant when deriving.
This change adds both FILS-SHA256 and FILS-SHA384 to the checks
for determining the SHA variant.
crypto_derive_pairwise_ptk was taking a boolean to decide whether to
use SHA1 or SHA256, but for FILS SHA384 may also be required for
rekeys depending on the AKM.
crypto_derive_pairwise_ptk was changed to take l_checksum_type instead
of a boolean to allow for all 3 SHA types.
With FILS support coming there needs to be a way to set the PTK directly.
Other AKMs derive the PTK via the 4-way handshake, but FILS computes the
PTK on its own.
OWE defines KEK/KCK lengths depending on group. This change adds a
case into handshake_get_key_sizes. With OWE we can determine the
key lengths based on the PMK length in the handshake.
Right now the PMK is hard coded to 32 bytes, which works for the vast
majority of cases. The only outlier is OWE which can generate a PMK
of 32, 48 or 64 bytes depending on the ECC group used. The PMK length
is already stored in the handshake, so now we can just pass that to
crypto_derive_pairwise_ptk
The crypto_ptk was hard coded for 16 byte KCK/KEK. Depending on the
AKM these can be up to 32 bytes. This changes completely removes the
crypto_ptk struct and adds getters to the handshake object for the
kck and kek. Like before the PTK is derived into a continuous buffer,
and the kck/kek getters take care of returning the proper key offset
depending on AKM.
To allow for larger than 16 byte keys aes_unwrap needed to be
modified to take the kek length.
Non-802.11 AKMs can define their own key lengths. Currently only OWE does
this, and the MIC/KEK/KCK lengths will be determined by the PMK length so
we need to save it.