From 8317b96e7de2c07b066f370ac782bfa2bfb52151 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 3 May 2019 11:59:51 -0700 Subject: [PATCH] fils: netdev: update to use auth_proto concepts --- src/fils.c | 122 +++++++++++++++++++++++---------------------------- src/fils.h | 14 +----- src/netdev.c | 107 ++++++++++++++++++++++---------------------- 3 files changed, 111 insertions(+), 132 deletions(-) diff --git a/src/fils.c b/src/fils.c index be211c45..aa063357 100644 --- a/src/fils.c +++ b/src/fils.c @@ -34,18 +34,19 @@ #include "src/util.h" #include "src/missing.h" #include "src/erp.h" +#include "src/auth-proto.h" #define FILS_NONCE_LEN 16 #define FILS_SESSION_LEN 8 struct fils_sm { + struct auth_proto ap; struct erp_state *erp; struct handshake_state *hs; void *user_data; fils_tx_authenticate_func_t auth; fils_tx_associate_func_t assoc; - fils_complete_func_t complete; uint8_t nonce[FILS_NONCE_LEN]; uint8_t anonce[FILS_NONCE_LEN]; @@ -58,15 +59,8 @@ struct fils_sm { uint8_t pmk[48]; size_t pmk_len; uint8_t pmkid[16]; - - bool in_auth : 1; }; -static void fils_failed(struct fils_sm *fils, uint16_t status, bool ap_reject) -{ - fils->complete(status, fils->in_auth, ap_reject, fils->user_data); -} - static void fils_derive_pmkid(struct fils_sm *fils, const uint8_t *erp_data, size_t len) { @@ -237,34 +231,20 @@ static int fils_derive_key_data(struct fils_sm *fils) fils->assoc(iov, 2, fils->kek_and_tk, fils->kek_len, data, FILS_NONCE_LEN * 2, fils->user_data); - fils->in_auth = false; - return 0; } -struct fils_sm *fils_sm_new(struct handshake_state *hs, - fils_tx_authenticate_func_t auth, - fils_tx_associate_func_t assoc, - fils_complete_func_t complete, void *user_data) +static bool fils_start(struct auth_proto *driver) { - struct fils_sm *fils; + struct fils_sm *fils = l_container_of(driver, struct fils_sm, ap); - fils = l_new(struct fils_sm, 1); - - fils->auth = auth; - fils->assoc = assoc; - fils->complete = complete; - fils->user_data = user_data; - fils->hs = hs; - fils->in_auth = true; - - fils->erp = erp_new(hs->erp_cache, fils_erp_tx_func, fils); - - return fils; + return erp_start(fils->erp); } -void fils_sm_free(struct fils_sm *fils) +static void fils_free(struct auth_proto *driver) { + struct fils_sm *fils = l_container_of(driver, struct fils_sm, ap); + erp_free(fils->erp); explicit_bzero(fils->ick, sizeof(fils->ick)); @@ -275,16 +255,10 @@ void fils_sm_free(struct fils_sm *fils) l_free(fils); } -void fils_start(struct fils_sm *fils) -{ - if (!erp_start(fils->erp)) - fils->complete(MMPDU_STATUS_CODE_UNSPECIFIED, fils->in_auth, - false, fils->user_data); -} - -void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, +static int fils_rx_authenticate(struct auth_proto *driver, const uint8_t *frame, size_t len) { + struct fils_sm *fils = l_container_of(driver, struct fils_sm, ap); const struct mmpdu_header *hdr = mpdu_validate(frame, len); const struct mmpdu_authentication *auth; struct ie_tlv_iter iter; @@ -295,27 +269,25 @@ void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, if (!hdr) { l_debug("Auth frame header did not validate"); - goto auth_failed; + return -EBADMSG; } auth = mmpdu_body(hdr); if (!auth) { l_debug("Auth frame body did not validate"); - goto auth_failed; + return -EBADMSG; } if (auth->status != 0) { l_debug("invalid status %u", auth->status); - fils_failed(fils, auth->status, true); - return; + return (int)auth->status; } if (auth->algorithm != MMPDU_AUTH_ALGO_FILS_SK && auth->algorithm != MMPDU_AUTH_ALGO_FILS_SK_PFS) { l_debug("invalid auth algorithm %u", auth->algorithm); - fils_failed(fils, MMPDU_STATUS_CODE_UNSUP_AUTH_ALG, false); - return; + return MMPDU_STATUS_CODE_UNSUP_AUTH_ALG; } ie_tlv_iter_init(&iter, auth->ies, (const uint8_t *) hdr + len - @@ -324,13 +296,13 @@ void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, switch (iter.tag) { case IE_TYPE_FILS_NONCE: if (iter.len != FILS_NONCE_LEN) - goto auth_failed; + goto invalid_ies; anonce = iter.data; break; case IE_TYPE_FILS_SESSION: if (iter.len != FILS_SESSION_LEN) - goto auth_failed; + goto invalid_ies; session = iter.data; break; @@ -345,24 +317,24 @@ void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, if (!anonce || !session || !wrapped) { l_debug("Auth did not include required IEs"); - fils_failed(fils, MMPDU_STATUS_CODE_INVALID_ELEMENT, false); - return; + goto invalid_ies; } memcpy(fils->anonce, anonce, FILS_NONCE_LEN); if (erp_rx_packet(fils->erp, wrapped, wrapped_len) < 0) - goto auth_failed; + goto invalid_ies; - fils_derive_key_data(fils); - return; + return fils_derive_key_data(fils); -auth_failed: - fils_failed(fils, MMPDU_REASON_CODE_UNSPECIFIED, false); +invalid_ies: + return MMPDU_STATUS_CODE_INVALID_ELEMENT; } -void fils_rx_associate(struct fils_sm *fils, const uint8_t *frame, size_t len) +static int fils_rx_associate(struct auth_proto *driver, const uint8_t *frame, + size_t len) { + struct fils_sm *fils = l_container_of(driver, struct fils_sm, ap); const struct mmpdu_header *hdr = mpdu_validate(frame, len); const struct mmpdu_association_response *assoc; struct ie_tlv_iter iter; @@ -381,20 +353,18 @@ void fils_rx_associate(struct fils_sm *fils, const uint8_t *frame, size_t len) if (!hdr) { l_debug("Assoc frame header did not validate"); - goto assoc_failed; + return -EBADMSG; } assoc = mmpdu_body(hdr); if (!assoc) { l_debug("Assoc frame body did not validate"); - goto assoc_failed;; + return -EBADMSG; } - if (assoc->status_code != 0) { - fils_failed(fils, assoc->status_code, true); - return; - } + if (assoc->status_code != 0) + return (int)assoc->status_code; ie_tlv_iter_init(&iter, assoc->ies, (const uint8_t *) hdr + len - assoc->ies); @@ -467,7 +437,7 @@ void fils_rx_associate(struct fils_sm *fils, const uint8_t *frame, size_t len) if (memcmp(ap_key_auth, expected_key_auth, fils->ick_len)) { l_error("AP KeyAuth did not verify"); - goto assoc_failed; + return -EBADMSG; } handshake_state_set_pmk(fils->hs, fils->pmk, fils->pmk_len); @@ -484,14 +454,32 @@ void fils_rx_associate(struct fils_sm *fils, const uint8_t *frame, size_t len) handshake_state_set_ptk(fils->hs, fils->kek_and_tk, fils->kek_len + 16); handshake_state_install_ptk(fils->hs); - fils->complete(0, fils->in_auth, false, fils->user_data); - - return; - -assoc_failed: - fils_failed(fils, MMPDU_STATUS_CODE_UNSPECIFIED, false); - return; + return 0; invalid_ies: - fils_failed(fils, MMPDU_STATUS_CODE_INVALID_ELEMENT, false); + return MMPDU_STATUS_CODE_INVALID_ELEMENT; +} + +struct auth_proto *fils_sm_new(struct handshake_state *hs, + fils_tx_authenticate_func_t auth, + fils_tx_associate_func_t assoc, + void *user_data) +{ + struct fils_sm *fils; + + fils = l_new(struct fils_sm, 1); + + fils->auth = auth; + fils->assoc = assoc; + fils->user_data = user_data; + fils->hs = hs; + + fils->ap.start = fils_start; + fils->ap.free = fils_free; + fils->ap.rx_authenticate = fils_rx_authenticate; + fils->ap.rx_associate = fils_rx_associate; + + fils->erp = erp_new(hs->erp_cache, fils_erp_tx_func, fils); + + return &fils->ap; } diff --git a/src/fils.h b/src/fils.h index 818ff455..f9e83d94 100644 --- a/src/fils.h +++ b/src/fils.h @@ -30,18 +30,8 @@ typedef void (*fils_tx_associate_func_t)(struct iovec *iov, size_t iov_len, const uint8_t *kek, size_t kek_len, const uint8_t *nonces, size_t nonces_len, void *user_data); -typedef void (*fils_complete_func_t)(uint16_t status, bool in_auth, - bool ap_reject, void *user_data); -struct fils_sm *fils_sm_new(struct handshake_state *hs, +struct auth_proto *fils_sm_new(struct handshake_state *hs, fils_tx_authenticate_func_t auth, fils_tx_associate_func_t assoc, - fils_complete_func_t complete, void *user_data); - -void fils_sm_free(struct fils_sm *fils); - -void fils_start(struct fils_sm *fils); - -void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, - size_t len); -void fils_rx_associate(struct fils_sm *fils, const uint8_t *frame, size_t len); + void *user_data); diff --git a/src/netdev.c b/src/netdev.c index b8f7e258..ff574d65 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -60,6 +60,7 @@ #include "src/nl80211util.h" #include "src/owe.h" #include "src/fils.h" +#include "src/auth-proto.h" #ifndef ENOTSUPP #define ENOTSUPP 524 @@ -97,7 +98,7 @@ struct netdev { struct eapol_sm *sm; struct sae_sm *sae_sm; struct owe_sm *owe; - struct fils_sm *fils; + struct auth_proto *ap; struct handshake_state *handshake; uint32_t connect_cmd_id; uint32_t disconnect_cmd_id; @@ -561,6 +562,11 @@ static void netdev_connect_free(struct netdev *netdev) netdev->owe = NULL; } + if (netdev->ap) { + auth_proto_free(netdev->ap); + netdev->ap = NULL; + } + eapol_preauth_cancel(netdev->index); if (netdev->handshake) { @@ -2350,6 +2356,8 @@ static void netdev_authenticate_event(struct l_genl_msg *msg, const void *data; const uint8_t *frame = NULL; size_t frame_len = 0; + int ret; + uint16_t status_code = MMPDU_STATUS_CODE_UNSPECIFIED; l_debug(""); @@ -2368,7 +2376,7 @@ static void netdev_authenticate_event(struct l_genl_msg *msg, * the FT Associate command is included in the attached frame and is * not available in the Authenticate command callback. */ - if (!netdev->in_ft && !netdev->sae_sm && !netdev->owe && !netdev->fils) + if (!netdev->in_ft && !netdev->sae_sm && !netdev->owe && !netdev->ap) return; if (!l_genl_attr_init(&attr, msg)) { @@ -2385,7 +2393,8 @@ static void netdev_authenticate_event(struct l_genl_msg *msg, if (netdev->sae_sm) { sae_timeout(netdev->sae_sm); return; - } + } else if (auth_proto_auth_timeout(netdev->ap)) + return; goto auth_error; @@ -2410,16 +2419,22 @@ static void netdev_authenticate_event(struct l_genl_msg *msg, frame + 26, frame_len - 26); else if (netdev->owe) owe_rx_authenticate(netdev->owe); - else if (netdev->fils) - fils_rx_authenticate(netdev->fils, frame, frame_len); - else + else if (netdev->ap) { + ret = auth_proto_rx_authenticate(netdev->ap, frame, frame_len); + if (ret == 0 || ret == -EAGAIN) + return; + else if (ret > 0) + status_code = (uint16_t)ret; + + goto auth_error; + } else goto auth_error; return; auth_error: netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED, - MMPDU_STATUS_CODE_UNSPECIFIED); + status_code); } static void netdev_associate_event(struct l_genl_msg *msg, @@ -2431,6 +2446,7 @@ static void netdev_associate_event(struct l_genl_msg *msg, size_t frame_len = 0; const uint8_t *frame = NULL; uint16_t status_code = MMPDU_STATUS_CODE_UNSPECIFIED; + int ret; l_debug(""); @@ -2438,7 +2454,7 @@ static void netdev_associate_event(struct l_genl_msg *msg, return; if (!netdev->owe && !netdev->in_ft && !netdev->handshake->mde && - !netdev->fils) + !netdev->ap) return; if (!l_genl_attr_init(&attr, msg)) { @@ -2450,6 +2466,10 @@ static void netdev_associate_event(struct l_genl_msg *msg, switch (type) { case NL80211_ATTR_TIMED_OUT: l_warn("association timed out"); + + if (auth_proto_assoc_timeout(netdev->ap)) + return; + goto assoc_failed; case NL80211_ATTR_FRAME: @@ -2466,9 +2486,27 @@ static void netdev_associate_event(struct l_genl_msg *msg, if (netdev->owe) { owe_rx_associate(netdev->owe, frame, frame_len); return; - } else if (netdev->fils) { - fils_rx_associate(netdev->fils, frame, frame_len); - return; + } else if (netdev->ap) { + ret = auth_proto_rx_associate(netdev->ap, frame, frame_len); + if (ret == 0) { + auth_proto_free(netdev->ap); + netdev->ap = NULL; + + netdev->sm = eapol_sm_new(netdev->handshake); + eapol_register(netdev->sm); + + goto auth_complete; + } else if (ret == -EAGAIN) { + /* + * Here to support OWE retries. OWE will retry + * internally, but a connect even will still be emitted. + */ + netdev->ignore_connect_event = true; + return; + } else if (ret > 0) + status_code = (uint16_t)ret; + + goto assoc_failed; } if (!netdev_ft_process_associate(netdev, frame, frame_len, @@ -2478,6 +2516,7 @@ static void netdev_associate_event(struct l_genl_msg *msg, if (status_code != 0) goto assoc_failed; +auth_complete: if (netdev->sm) { /* * Start processing EAPoL frames now that the state machine @@ -2786,44 +2825,6 @@ static void netdev_fils_tx_associate(struct iovec *iov, size_t iov_len, } } -static void netdev_fils_complete(uint16_t status, bool in_auth, bool ap_reject, - void *user_data) -{ - struct netdev *netdev = user_data; - - fils_sm_free(netdev->fils); - netdev->fils = NULL; - - if (status == 0) { - netdev->ignore_connect_event = true; - - /* Register SM for rekeying */ - netdev->sm = eapol_sm_new(netdev->handshake); - eapol_register(netdev->sm); - eapol_set_started(netdev->sm); - - return; - } - - /* - * There are a few scenarios here: - * - * 1. AP rejected authentication, this case we are done. - * 2. AP accepted either authentication or association where status was - * zero, but we failed for some other reason. In these cases we - * should set expect_connect_failure which causes a deauth. - * 3. AP rejected association. This will be a non zero status code, so - * the kernel should know that we have failed the connection. - */ - - if (!ap_reject) - netdev->expect_connect_failure = true; - - netdev->result = (in_auth) ? NETDEV_RESULT_AUTHENTICATION_FAILED : - NETDEV_RESULT_ASSOCIATION_FAILED; - netdev->last_code = status; -} - static struct l_genl_msg *netdev_build_cmd_connect(struct netdev *netdev, struct scan_bss *bss, struct handshake_state *hs, @@ -2958,8 +2959,8 @@ static int netdev_connect_common(struct netdev *netdev, sae_start(netdev->sae_sm); else if (netdev->owe) owe_start(netdev->owe); - else if (netdev->fils) - fils_start(netdev->fils); + else + auth_proto_start(netdev->ap); return 0; } @@ -2993,9 +2994,9 @@ int netdev_connect(struct netdev *netdev, struct scan_bss *bss, break; case IE_RSN_AKM_SUITE_FILS_SHA256: case IE_RSN_AKM_SUITE_FILS_SHA384: - netdev->fils = fils_sm_new(hs, netdev_fils_tx_authenticate, + netdev->ap = fils_sm_new(hs, netdev_fils_tx_authenticate, netdev_fils_tx_associate, - netdev_fils_complete, netdev); + netdev); break; default: cmd_connect = netdev_build_cmd_connect(netdev, bss, hs, NULL);