From 37811a092c13c46207ae8e5dd17ddb6b52c6b424 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 29 Apr 2021 16:08:36 -0700 Subject: [PATCH] ft: create class for FT-over-DS targets FT-over-DS is being separated into two independent stages. The first of which is the processing of the action frame response. This new class will hold all the parsed information from the action frame and allowing it to be retrieved at a later time when IWD needs to roam. Initial info class should be created when the action frame is being sent out. Once a response is received it can be parsed with ft_over_ds_parse_action_response. This verifies the frame and updates the ft_ds_info class with the parsed data. ft_over_ds_prepare_handshake is the final step prior to Reassociation. This sets all the stored IEs, anonce, and KH IDs into the handshake and derives the new PTK. --- src/ft.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ft.h | 25 +++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/src/ft.c b/src/ft.c index 032eefd1..d482e539 100644 --- a/src/ft.c +++ b/src/ft.c @@ -488,6 +488,35 @@ static bool mde_equal(const uint8_t *mde1, const uint8_t *mde2) return memcmp(mde1, mde1, mde1[1] + 2) == 0; } +static bool ft_over_ds_process_ies(struct ft_ds_info *info, + struct handshake_state *hs, + const uint8_t *ies, + size_t ies_len) +{ + const uint8_t *mde = NULL; + const uint8_t *fte = NULL; + bool is_rsn = hs->supplicant_ie != NULL; + + if (ft_parse_ies(hs, ies, ies_len, &mde, &fte) < 0) + return false; + + if (!mde_equal(info->mde, mde)) + goto ft_error; + + if (is_rsn) { + if (!ft_parse_fte(hs, info->snonce, fte, &info->ft_info)) + goto ft_error; + + info->fte = l_memdup(fte, fte[1] + 2); + } else if (fte) + goto ft_error; + + return true; + +ft_error: + return false; +} + static int ft_process_ies(struct handshake_state *hs, const uint8_t *ies, size_t ies_len) { @@ -530,6 +559,59 @@ ft_error: return -EBADMSG; } +int ft_over_ds_parse_action_response(struct ft_ds_info *info, + struct handshake_state *hs, + const uint8_t *frame, size_t frame_len) +{ + uint16_t status; + + if (frame_len < 16) + return -EINVAL; + + /* Category FT */ + if (frame[0] != 6) + return -EINVAL; + + /* FT Action */ + if (frame[1] != 2) + return -EINVAL; + + if (memcmp(frame + 2, info->spa, 6)) + return -ENOENT; + if (memcmp(frame + 8, info->aa, 6)) + return -ENOENT; + + status = l_get_le16(frame + 14); + if (status != 0) + return (int)status; + + if (!ft_over_ds_process_ies(info, hs, frame + 16, frame_len - 16)) + return -EBADMSG; + + return 0; +} + +bool ft_over_ds_prepare_handshake(struct ft_ds_info *info, + struct handshake_state *hs) +{ + if (!hs->supplicant_ie) + return true; + + memcpy(hs->snonce, info->snonce, sizeof(hs->snonce)); + + handshake_state_set_fte(hs, info->fte); + + handshake_state_set_anonce(hs, info->ft_info.anonce); + + handshake_state_set_kh_ids(hs, info->ft_info.r0khid, + info->ft_info.r0khid_len, + info->ft_info.r1khid); + + handshake_state_derive_ptk(hs); + + return true; +} + static int ft_rx_action(struct auth_proto *ap, const uint8_t *frame, size_t frame_len) { @@ -558,6 +640,17 @@ auth_error: return (int)status_code; } +void ft_ds_info_free(struct ft_ds_info *info) +{ + __typeof__(info->free) destroy = info->free; + + if (info->fte) + l_free(info->fte); + + if (destroy) + destroy(info); +} + static int ft_rx_authenticate(struct auth_proto *ap, const uint8_t *frame, size_t frame_len) { diff --git a/src/ft.h b/src/ft.h index f24b3b5e..907c3d5d 100644 --- a/src/ft.h +++ b/src/ft.h @@ -20,15 +20,37 @@ * */ +struct handshake_state; + typedef void (*ft_tx_authenticate_func_t)(struct iovec *iov, size_t iov_len, void *user_data); typedef void (*ft_tx_associate_func_t)(struct iovec *ie_iov, size_t iov_len, void *user_data); +typedef void (*ft_ds_free_func_t)(void *user_data); + +struct ft_ds_info { + uint8_t spa[6]; + uint8_t aa[6]; + uint8_t snonce[32]; + uint8_t mde[3]; + uint8_t *fte; + + struct ie_ft_info ft_info; + + void (*free)(struct ft_ds_info *s); +}; + +void ft_ds_info_free(struct ft_ds_info *info); + bool ft_build_authenticate_ies(struct handshake_state *hs, const uint8_t *new_snonce, uint8_t *buf, size_t *len); +int ft_over_ds_parse_action_response(struct ft_ds_info *info, + struct handshake_state *hs, + const uint8_t *frame, size_t frame_len); + struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs, ft_tx_authenticate_func_t tx_auth, ft_tx_associate_func_t tx_assoc, @@ -38,3 +60,6 @@ struct auth_proto *ft_over_ds_sm_new(struct handshake_state *hs, ft_tx_authenticate_func_t tx_auth, ft_tx_associate_func_t tx_assoc, void *user_data); + +bool ft_over_ds_prepare_handshake(struct ft_ds_info *info, + struct handshake_state *hs);