From patchwork Sat Sep 24 21:07:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: michael-dev X-Patchwork-Id: 674375 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3shNDB4vY1z9s4n for ; Sun, 25 Sep 2016 07:10:10 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fami-braun.de header.i=@fami-braun.de header.b=rZyAjAK4; dkim-atps=neutral Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bnuCn-0000z8-Cx; Sat, 24 Sep 2016 21:09:53 +0000 Received: from mo6-p00-ob.smtp.rzone.de ([2a01:238:20a:202:5300::3]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bnuBi-0000Py-0j for hostap@lists.infradead.org; Sat, 24 Sep 2016 21:08:55 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1474751298; l=10851; s=domk; d=fami-braun.de; h=References:In-Reply-To:Date:Subject:To:From; bh=YqL0+9c3x3VHCL9SUFfcERf/skktggIGEKUo1N4hHzs=; b=rZyAjAK40rRc6qT1Wz5nS+iFitVuhbpSFnFb28Zq1zmjFOt9YACi/937fbqngeOauLL 7hhlqf13iW96vDtKTSiQXOHqYekz9JfZqifUrrm+asZ5iIXOvgGeepQRUXgIEufJm+q6N 4GEzrPU+uwJkjzWhE4M/OlbKSuNkwxMQFJY= X-RZG-AUTH: :P20JeEWkefDI1ODZs1HHtgV3eF0OpFsRaGIBBWYxhJvJPtnXtogBWn6YvUkYzDKvBT07wx/0LJ4BNA== X-RZG-CLASS-ID: mo00 Received: from dynamic.fami-braun.de ([2a01:198:45f::254]) by smtp.strato.de (RZmta 39.3 AUTH) with ESMTPSA id R08d48s8OL8IIHI (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA)) (Client did not present a certificate) for ; Sat, 24 Sep 2016 23:08:18 +0200 (CEST) Received: from dynamic.fami-braun.de (localhost [127.0.0.1]) by dynamic.fami-braun.de (fami-braun.de) with ESMTP id 4B1B41540F3 for ; Sat, 24 Sep 2016 23:08:18 +0200 (CEST) Received: by dynamic.fami-braun.de (fami-braun.de, from userid 1001) id 34A1F158298; Sat, 24 Sep 2016 23:08:18 +0200 (CEST) From: "M. Braun" To: hostap@lists.infradead.org Subject: [PATCH v2 07/33] FT: resend pull request Date: Sat, 24 Sep 2016 23:07:51 +0200 Message-Id: <1474751297-7277-8-git-send-email-michael-dev@fami-braun.de> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1474751297-7277-1-git-send-email-michael-dev@fami-braun.de> References: <1474751297-7277-1-git-send-email-michael-dev@fami-braun.de> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160924_140846_443777_77473B30 X-CRM114-Status: GOOD ( 18.29 ) X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [2a01:238:20a:202:5300:0:0:3 listed in] [list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Michael Braun Add a timeout and retry pull request. Do not change nonce during resend in order to accept response to initial request. Signed-off-by: Michael Braun --- hostapd/config_file.c | 4 +++ hostapd/hostapd.conf | 5 ++++ src/ap/ap_config.c | 2 ++ src/ap/ap_config.h | 2 ++ src/ap/wpa_auth.c | 3 +++ src/ap/wpa_auth.h | 3 +++ src/ap/wpa_auth_ft.c | 68 ++++++++++++++++++++++++++++++++++++++++++-------- src/ap/wpa_auth_glue.c | 2 ++ src/ap/wpa_auth_i.h | 1 + 9 files changed, 80 insertions(+), 10 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 288cdf1..1a8b5f2 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2545,6 +2545,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->reassociation_deadline = atoi(pos); } else if (os_strcmp(buf, "rkh_pos_timeout") == 0) { bss->rkh_pos_timeout = atoi(pos); + } else if (os_strcmp(buf, "rkh_pull_timeout") == 0) { + bss->rkh_pull_timeout = atoi(pos); + } else if (os_strcmp(buf, "rkh_pull_retries") == 0) { + bss->rkh_pull_retries = atoi(pos); } else if (os_strcmp(buf, "r0kh") == 0) { if (add_r0kh(bss, pos) < 0) { wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'", diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index c6b8cae..24cd3e1 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1327,6 +1327,11 @@ own_ip_addr=127.0.0.1 # Special values: 0 -> do not cache; -1 -> do not expire #rkh_pos_timeout = 86400 (default = 1d) +# Timeout (milli seconds) for requesting PMK-R1 from R0KH using PULL request +# and number of retries. +#rkh_pull_timeout = 1000 (default = 1s) +#rkh_pull_retries = 4 (default) + # Whether PMK-R1 push is enabled at R0KH # 0 = do not push PMK-R1 to all configured R1KHs (default) # 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index b43890d..35fe74d 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -91,6 +91,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_IEEE80211R bss->ft_over_ds = 1; bss->rkh_pos_timeout = 86400; + bss->rkh_pull_timeout = 1000; + bss->rkh_pull_retries = 4; #endif /* CONFIG_IEEE80211R */ bss->radius_das_time_window = 300; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 51f9d5d..438da47 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -335,6 +335,8 @@ struct hostapd_bss_config { u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; int rkh_pos_timeout; + int rkh_pull_timeout; /* ms */ + int rkh_pull_retries; u32 reassociation_deadline; struct ft_remote_r0kh *r0kh_list; struct ft_remote_r1kh *r1kh_list; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 4d88376..9101665 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -690,6 +690,9 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); +#ifdef CONFIG_IEEE80211R + wpa_ft_sta_deinit(sm); +#endif /* CONFIG_IEEE80211R */ if (sm->in_step_loop) { /* Must not free state machine while wpa_sm_step() is running. * Freeing will be completed in the end of wpa_sm_step(). */ diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 8abb5e2..6a3497a 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -169,6 +169,8 @@ struct wpa_auth_config { u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; int rkh_pos_timeout; + int rkh_pull_timeout; /* ms */ + int rkh_pull_retries; u32 reassociation_deadline; struct ft_remote_r0kh **r0kh_list; struct ft_remote_r1kh **r1kh_list; @@ -333,6 +335,7 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, const u8 *data, size_t data_len); void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); void wpa_ft_deinit(struct wpa_authenticator *wpa_auth); +void wpa_ft_sta_deinit(struct wpa_state_machine *sm); #endif /* CONFIG_IEEE80211R */ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index fd727fe..4e66fde 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -28,6 +28,8 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm, const u8 *current_ap, const u8 *sta_addr, u16 status, const u8 *resp_ies, size_t resp_ies_len); +static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx); +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx); static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, @@ -412,6 +414,13 @@ static void wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth, } +void wpa_ft_sta_deinit(struct wpa_state_machine *sm) +{ + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL); +} + + void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) { eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth, ELOOP_ALL_CTX); @@ -419,12 +428,29 @@ void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) } +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx) +{ + /* cancel multiple timeouts */ + eloop_cancel_timeout(wpa_ft_expire_pull, eloop_ctx, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, eloop_ctx, NULL); + ft_pull_resp_cb_finish(eloop_ctx, timeout_ctx); +} + + static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, const u8 *ies, size_t ies_len, const u8 *pmk_r0_name) { struct ft_remote_r0kh *r0kh, *r0kh_wildcard = NULL; struct ft_r0kh_r1kh_pull_frame frame, f; + int tsecs, tusecs, first; + struct wpabuf *ft_pending_req_ies; + + if (sm->ft_pending_pull_left_retries <= 0) + return -1; + first = (sm->ft_pending_pull_left_retries == + sm->wpa_auth->conf.rkh_pull_retries); + sm->ft_pending_pull_left_retries--; if (!sm->wpa_auth->conf.r0kh_list) return -1; @@ -459,13 +485,17 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, /* aes_wrap() does not support inplace encryption, so use a temporary * buffer for the data. */ - if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) { - wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " - "nonce"); - return -1; - } - os_memcpy(sm->ft_pending_pull_nonce, f.nonce, - FT_R0KH_R1KH_PULL_NONCE_LEN); + if (first) { + if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) { + wpa_printf(MSG_DEBUG, "FT: Failed to get random data " + "for nonce"); + return -1; + } + os_memcpy(sm->ft_pending_pull_nonce, f.nonce, + FT_R0KH_R1KH_PULL_NONCE_LEN); + } else + os_memcpy(f.nonce, sm->ft_pending_pull_nonce, + FT_R0KH_R1KH_PULL_NONCE_LEN); os_memcpy(f.r0kh_id, sm->r0kh_id, FT_R0KH_ID_MAX_LEN); f.r0kh_id_len = sm->r0kh_id_len; os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); @@ -478,11 +508,16 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, f.nonce, frame.nonce) < 0) return -1; + ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); wpabuf_free(sm->ft_pending_req_ies); - sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); + sm->ft_pending_req_ies = ft_pending_req_ies; if (sm->ft_pending_req_ies == NULL) return -1; + tsecs = sm->wpa_auth->conf.rkh_pull_timeout / 1000; + tusecs = (sm->wpa_auth->conf.rkh_pull_timeout % 1000) * 1000; + eloop_register_timeout(tsecs, tusecs, wpa_ft_expire_pull, sm, NULL); + wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame)); return 0; @@ -1192,6 +1227,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, sm->ft_pending_cb = cb; sm->ft_pending_cb_ctx = ctx; sm->ft_pending_auth_transaction = auth_transaction; + sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries; res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies, &resp_ies_len); if (res < 0) { @@ -1468,6 +1504,7 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb; sm->ft_pending_cb_ctx = sm; os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN); + sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries; res = wpa_ft_process_auth_req(sm, body, len, &resp_ies, &resp_ies_len); if (res < 0) { @@ -1650,13 +1687,20 @@ static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx) size_t resp_ies_len; u16 status; + if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL) + return; + res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies), wpabuf_len(sm->ft_pending_req_ies), &resp_ies, &resp_ies_len); + if (res < 0) { + /* this loop is broken by ft_pending_pull_left_retries */ + wpa_printf(MSG_DEBUG, "FT: Callback postponed until response " + "is available"); + return; + } wpabuf_free(sm->ft_pending_req_ies); sm->ft_pending_req_ies = NULL; - if (res < 0) - res = WLAN_STATUS_UNSPECIFIED_FAILURE; status = res; wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR " - status %u", MAC2STR(sm->addr), status); @@ -1689,6 +1733,10 @@ static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx) wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for " MACSTR " - process from timeout", MAC2STR(sm->addr)); + + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL); + eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL); if (info->r0kh_wildcard && sm->wpa_auth->conf.rkh_pos_timeout) diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index c99aefc..57ca999 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -70,6 +70,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->r0_key_lifetime = conf->r0_key_lifetime; wconf->reassociation_deadline = conf->reassociation_deadline; wconf->rkh_pos_timeout = conf->rkh_pos_timeout; + wconf->rkh_pull_timeout = conf->rkh_pull_timeout; + wconf->rkh_pull_retries = conf->rkh_pull_retries; wconf->r0kh_list = &conf->r0kh_list; wconf->r1kh_list = &conf->r1kh_list; wconf->pmk_r1_push = conf->pmk_r1_push; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 72b7eb3..c634c32 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -131,6 +131,7 @@ struct wpa_state_machine { u8 ft_pending_pull_nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; u8 ft_pending_auth_transaction; u8 ft_pending_current_ap[ETH_ALEN]; + int ft_pending_pull_left_retries; #endif /* CONFIG_IEEE80211R */ int pending_1_of_4_timeout;