From patchwork Mon Jan 15 16:08:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dariusz Kopka X-Patchwork-Id: 1886746 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=NYZZCiVJ; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=j8r3p9S0; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TDHCT3n7Zz1yPJ for ; Tue, 16 Jan 2024 03:09:41 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:To:Cc:Date:Message-Id:Subject: Mime-Version:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=zx50Q1Mx8SvOyKedeUhL4UDJOdw0CGe0OYCEv2lLCyk=; b=NYZ ZCiVJp+Uep6mGq1fLCHetllZCTQwjBvhC+IcS+5Ce2hotkuknkqi0oczhx3lCK7t2QSKUG0MG8g2y HCfSboaa87S+2feQ7LQxN5d3KGVk2ioBMcWp8HCzY0KqbJWV98p/LkKDADYo8ah6NDOsJ805ZNyG8 iWhcEML3x3GcZpTy+naOWm4JurBe4DyDmB5IcXs1Xu3fSy5m+t8Crz8rSAtHyoX2uyt8xbxKJWu/J /W43LmNt8dRhdy6qftI32jv1v3bVCOJp5xf2zxqaVwSMEvD2KHcs0MHQAsAXevp9lIoqY+UwkXNyI FZm0q5w6ZL86M46PEOAt4B5x1/akvTA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1rPPWH-009YxY-0w; Mon, 15 Jan 2024 16:09:01 +0000 Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1rPPWC-009Yu6-1E for hostap@lists.infradead.org; Mon, 15 Jan 2024 16:08:59 +0000 Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-40e69b3149fso31463485e9.3 for ; Mon, 15 Jan 2024 08:08:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1705334932; x=1705939732; darn=lists.infradead.org; h=to:cc:date:message-id:subject:mime-version :content-transfer-encoding:from:from:to:cc:subject:date:message-id :reply-to; bh=fsrXItJCKNMrqVeSu0G0OAP/t8T35UkYKSP3fgfM4Cw=; b=j8r3p9S0uuuLaxy2gGHQ1w8t1rOMCfGdmsgeAoHWMG6Vwuq53/xODvSC+oRS5/9n0m gylvYL8R81ZwkeA7LdJ1XM116EOg3VRh69kPiPypKuTjotDGZGOeSh/fj3eJZ6fQ37Jd CG7wwZH6szQMly/r6VSmB0Uu7mAdy0eC7A04O6sfElYsOH23DI5fzHAGohVkuPQ2cgE6 WF/SI9+G79i1h5ZJw/xBaa1ijOFlfM4ik0yJ2gG4WAdGjSCJFtoK+/rKJRHarUH9jJP/ RndkjvtsghEBfIJZRye0g+xl1s8Mp/pLPuNWe0VovzhadP2tRbLuG7X+rsXieEXL3wh5 Be2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705334932; x=1705939732; h=to:cc:date:message-id:subject:mime-version :content-transfer-encoding:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fsrXItJCKNMrqVeSu0G0OAP/t8T35UkYKSP3fgfM4Cw=; b=vACmn6aerKrUnfASOESw0K+FLnEegH/PjuM3syjJV2FQgmNupl9kY9KB9Or2XjJNcT gxV7TaS4/AClszPXPvGB1bc2EjK+WZV7owgZXZS5nH16mUyo+Y6dbUTnVvngQ7gBeDAf pTKa6f3bCGkg1CUCg6kkjdWqPa6+Er8cGIxYEmObSth8I18Q8nDXpsOrv6gwfND/hTRi T0dl9RxpTrEoC9iVLrUDN0F9RVzs1BUa7xtgaCe5f4vIQszsG0SfTKh5e5DpctAyK5K2 jS2R+c7a8+27YPW1s6u3cBT4n5S2GJmm8XuRd5wsCNnowi3Pg/2Wd+/SQ2+e/bP6ojrc 1Z2w== X-Gm-Message-State: AOJu0YyTTYeZC0o9ROrqMbua7/Zzvp1Fjz8MMJaUhQ4U/n6f7Rfe0OpB voFD0e7674u6CB29tRP6HEE6uDsWXk9Zww== X-Google-Smtp-Source: AGHT+IEHBvGXOUSOlGtC1QzW7pMT8YGj9HR19Vrv2jgPfrBT3vnUfq9QFsO90va4tdIrNFoD4W7Amw== X-Received: by 2002:a05:600c:470c:b0:40e:46ca:8c5c with SMTP id v12-20020a05600c470c00b0040e46ca8c5cmr3147517wmo.109.1705334931395; Mon, 15 Jan 2024 08:08:51 -0800 (PST) Received: from smtpclient.apple (83.10.85.205.ipv4.supernova.orange.pl. [83.10.85.205]) by smtp.gmail.com with ESMTPSA id wr8-20020a170907700800b00a2e08b24ea3sm744395ejb.174.2024.01.15.08.08.50 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 15 Jan 2024 08:08:51 -0800 (PST) From: Dariusz Kopka Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3774.300.61.1.2\)) Subject: [PATCH] Add dynamic reload of RxKH definitions from file Message-Id: Date: Mon, 15 Jan 2024 17:08:40 +0100 Cc: Dariusz Kopka , michal@plume.com To: hostap@lists.infradead.org X-Mailer: Apple Mail (2.3774.300.61.1.2) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240115_080856_429809_8430E753 X-CRM114-Status: GOOD ( 25.24 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From 09f58a12e50f8e7b09d485b56154f2be0957da21 Mon Sep 17 00:00:00 2001 From: Dariusz Kopka Date: Mon, 15 Jan 2024 14:16:00 +0100 Subject: [PATCH] Add dynamic reload of RxKH definitions from file Hostapd reads the list of Rx Key Holders from hostapd.conf file. However, for systems where topology changes dynamically, the update of RxKHs list is required without reloading the whole configuration [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2a00:1450:4864:20:0:0:0:32c listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [darkopka[at]gmail.com] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From 09f58a12e50f8e7b09d485b56154f2be0957da21 Mon Sep 17 00:00:00 2001 From: Dariusz Kopka Date: Mon, 15 Jan 2024 14:16:00 +0100 Subject: [PATCH] Add dynamic reload of RxKH definitions from file Hostapd reads the list of Rx Key Holders from hostapd.conf file. However, for systems where topology changes dynamically, the update of RxKHs list is required without reloading the whole configuration. Here we introduce a new source of RxKH definition with original syntax: - rxkh_file - path to a file containing a list of RxKHs. In addition two cli commands are added: - get_rxkhs - returns the list of currently configured RxKHs - reload_rxkhs - reloads RxKHs definition from a file specified in `rxkh_file` This allows hostapd to properly distribute Rx keys even after topology change (assuming rxkh_file is updated and reload_rxkhs command issued). Syntax of rxkh_file is the same as extraction of r0kh and r1kh options from original hostapd.conf file. ``` r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeef r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeef r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeef ``` Signed-off-by: Dariusz Kopka --- hostapd/config_file.c | 79 +++++++++++++++++++++++++++++++++++++++++++ hostapd/ctrl_iface.c | 76 +++++++++++++++++++++++++++++++++++++++++ hostapd/hostapd.conf | 6 ++++ hostapd/hostapd_cli.c | 22 ++++++++++++ src/ap/ap_config.c | 53 ++++++++++++++++++----------- src/ap/ap_config.h | 5 +++ 6 files changed, 221 insertions(+), 20 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 15aaca924..0c1e30604 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1020,6 +1020,73 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value) return 0; } + +int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf, + const char *fname) +{ + FILE *f; + char buf[256], *pos; + int line = 0, errors = 0; + + if (!fname) + return 0; + + f = fopen(fname, "r"); + if (!f) { + wpa_printf(MSG_ERROR, "rxkh file '%s' not found.", fname); + return -1; + } + + while (fgets(buf, sizeof(buf), f)) { + line++; + + if (buf[0] == '#') + continue; + pos = buf; + while (*pos != '\0') { + if (*pos == '\n') { + *pos = '\0'; + break; + } + pos++; + } + if (buf[0] == '\0') + continue; + + pos = os_strchr(buf, '='); + if (pos == NULL) { + wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'", + line, buf); + errors++; + continue; + } + *pos = '\0'; + pos++; + + if (os_strcmp(buf, "r0kh") == 0) { + if (add_r0kh(conf, pos) < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid r0kh '%s'", + line, pos); + errors++; + } + } else if (os_strcmp(buf, "r1kh") == 0) { + if (add_r1kh(conf, pos) < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid r1kh '%s'", + line, pos); + errors++; + } + } + } + + fclose(f); + + if (errors) { + wpa_printf(MSG_ERROR, "%d errors in configuring rxkhs from " + "'%s'", errors, fname); + return -1; + } + return 0; +} #endif /* CONFIG_IEEE80211R_AP */ @@ -3098,6 +3165,18 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "rxkh_file") == 0) { + os_free(bss->rxkh_file); + bss->rxkh_file = os_strdup(pos); + if (!bss->rxkh_file) { + wpa_printf(MSG_ERROR, "Line %d: allocation failed", + line); + return 1; + } + if (hostapd_config_read_rxkh_file(bss, pos)) { + wpa_printf(MSG_DEBUG, "Line %d: failed to read rxkh_file '%s'", + line, pos); + } } else if (os_strcmp(buf, "pmk_r1_push") == 0) { bss->pmk_r1_push = atoi(pos); } else if (os_strcmp(buf, "ft_over_ds") == 0) { diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 273e7bd7e..913165124 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -974,6 +974,74 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211R_AP +static int hostapd_ctrl_iface_get_rxkhs(struct hostapd_data *hapd, + char *buf, size_t buflen) +{ + int i; + int ret; + char *pos, *end; + struct ft_remote_r0kh *r0kh; + struct ft_remote_r1kh *r1kh; + struct hostapd_bss_config *conf = hapd->conf; + + pos = buf; + end = buf + buflen; + + for(r0kh = conf->r0kh_list; r0kh; r0kh=r0kh->next) { + ret = os_snprintf(pos, end - pos, "r0kh=" MACSTR " ", + MAC2STR(r0kh->addr)); + pos += ret; + ret = os_snprintf(pos, r0kh->id_len + 2, "%s ", + r0kh->id); + pos += ret; + for (i = 0; i<32; i++) { + ret = os_snprintf(pos, 3, "%02x", r0kh->key[i]); + pos += ret; + } + ret = os_snprintf(pos, 2, "\n"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + for(r1kh = conf->r1kh_list; r1kh; r1kh=r1kh->next) { + ret = os_snprintf(pos, end - pos, "r1kh=" MACSTR " " MACSTR " ", + MAC2STR(r1kh->addr), MAC2STR(r1kh->id)); + pos += ret; + for (i = 0; i<32; i++) { + ret = os_snprintf(pos, 3, "%02x", r1kh->key[i]); + pos += ret; + } + ret = os_snprintf(pos, 2, "\n"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + return pos - buf; +} + + +static int hostapd_ctrl_iface_reload_rxkhs(struct hostapd_data *hapd) +{ + struct hostapd_bss_config *conf = hapd->conf; + int err; + + hostapd_config_clear_rxkhs(conf); + + err = hostapd_config_setup_rxkhs(conf); + if (err < 0) { + wpa_printf(MSG_ERROR, "Reloading RXKHs failed: %d", + err); + return -1; + } + + return 0; +} +#endif /* CONFIG_IEEE80211R_AP */ + + static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, char *buf, size_t buflen) { @@ -3599,6 +3667,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) { if (hostapd_ctrl_iface_reload_wpa_psk(hapd)) reply_len = -1; +#ifdef CONFIG_IEEE80211R_AP + } else if (os_strcmp(buf, "GET_RXKHS") == 0) { + reply_len = hostapd_ctrl_iface_get_rxkhs(hapd, reply, + reply_size); + } else if (os_strcmp(buf, "RELOAD_RXKHS") == 0) { + if (hostapd_ctrl_iface_reload_rxkhs(hapd)) + reply_len = -1; +#endif /* CONFIG_IEEE80211R_AP */ } else if (os_strcmp(buf, "RELOAD_BSS") == 0) { if (hostapd_ctrl_iface_reload_bss(hapd)) reply_len = -1; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 1aeeb7353..20ad28565 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -2295,6 +2295,12 @@ own_ip_addr=127.0.0.1 # list and thus will receive push notifications. #r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff +# Optionally, the list of RxKHs can be read from a text file. Format is the same +# as specified above. File shall contain both r0kh and r1kh. Once this variable +# is set, RxKHs can be reloaded in runtime without bringing down an interface +# using 'reload_rxkhs' command. +#rxkh_file= + # Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above) # Special values: 0 -> do not expire # Warning: do not cache implies no sequence number validation with wildcards diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index be3c23ca9..0db0470a2 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1407,6 +1407,22 @@ static int hostapd_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc, } +#ifdef CONFIG_IEEE80211R_AP +static int hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "GET_RXKHS"); +} + +static int hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOAD_RXKHS"); +} + +#endif /* CONFIG_IEEE80211R_AP */ + + #ifdef CONFIG_DPP static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, @@ -1804,6 +1820,12 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { " [req_mode=] = send a Beacon report request to a station" }, { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, "= reload wpa_psk_file only" }, +#ifdef CONFIG_IEEE80211R_AP + { "reload_rxkhs", hostapd_cli_cmd_reload_rxkhs, NULL, + "= reload R0KHs and R1KHs" }, + { "get_rxkhs", hostapd_cli_cmd_get_rxkhs, NULL, + "= get R0KHs and R1KHs" }, +#endif /* CONFIG_IEEE80211R_AP */ #ifdef ANDROID { "driver", hostapd_cli_cmd_driver, NULL, " [] = send driver command data" }, diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 040f39e7f..6ffecdaed 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -699,6 +699,36 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l) } +#ifdef CONFIG_IEEE80211R_AP +int hostapd_config_setup_rxkhs(struct hostapd_bss_config *conf) +{ + return hostapd_config_read_rxkh_file(conf, conf->rxkh_file); +} + +void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf) +{ + struct ft_remote_r0kh *r0kh, *r0kh_prev; + struct ft_remote_r1kh *r1kh, *r1kh_prev; + + r0kh = conf->r0kh_list; + conf->r0kh_list = NULL; + while (r0kh) { + r0kh_prev = r0kh; + r0kh = r0kh->next; + os_free(r0kh_prev); + } + + r1kh = conf->r1kh_list; + conf->r1kh_list = NULL; + while (r1kh) { + r1kh_prev = r1kh; + r1kh = r1kh->next; + os_free(r1kh_prev); + } +} +#endif /* CONFIG_IEEE80211R_AP */ + + static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf) { struct anqp_element *elem; @@ -831,26 +861,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->time_zone); #ifdef CONFIG_IEEE80211R_AP - { - struct ft_remote_r0kh *r0kh, *r0kh_prev; - struct ft_remote_r1kh *r1kh, *r1kh_prev; - - r0kh = conf->r0kh_list; - conf->r0kh_list = NULL; - while (r0kh) { - r0kh_prev = r0kh; - r0kh = r0kh->next; - os_free(r0kh_prev); - } - - r1kh = conf->r1kh_list; - conf->r1kh_list = NULL; - while (r1kh) { - r1kh_prev = r1kh; - r1kh = r1kh->next; - os_free(r1kh_prev); - } - } + hostapd_config_clear_rxkhs(conf); + os_free(conf->rxkh_file); + conf->rxkh_file = NULL; #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_WPS diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 1d3949559..b5993595d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -405,6 +405,7 @@ struct hostapd_bss_config { int ft_over_ds; int ft_psk_generate_local; int r1_max_key_lifetime; + char *rxkh_file; #endif /* CONFIG_IEEE80211R_AP */ char *ctrl_interface; /* directory for UNIX domain sockets */ @@ -1345,6 +1346,10 @@ void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr); void hostapd_config_free_eap_user(struct hostapd_eap_user *user); void hostapd_config_free_eap_users(struct hostapd_eap_user *user); void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p); +int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf, + const char *fname); +void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf); +int hostapd_config_setup_rxkhs(struct hostapd_bss_config *conf); void hostapd_config_free_bss(struct hostapd_bss_config *conf); void hostapd_config_free(struct hostapd_config *conf); int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,