diff options
Diffstat (limited to 'package/network/services/hostapd/patches')
70 files changed, 13212 insertions, 1626 deletions
diff --git a/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch b/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch index 84fc1c93513..269dcaac75c 100644 --- a/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch +++ b/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch @@ -16,7 +16,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net> --- a/src/crypto/crypto_wolfssl.c +++ b/src/crypto/crypto_wolfssl.c -@@ -1303,6 +1303,7 @@ int ecc_projective_add_point(ecc_point * +@@ -1340,6 +1340,7 @@ int ecc_projective_add_point(ecc_point * struct crypto_ec { ecc_key key; @@ -24,7 +24,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net> mp_int a; mp_int prime; mp_int order; -@@ -1357,6 +1358,8 @@ struct crypto_ec * crypto_ec_init(int gr +@@ -1394,6 +1395,8 @@ struct crypto_ec * crypto_ec_init(int gr return NULL; if (wc_ecc_init(&e->key) != 0 || @@ -33,7 +33,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net> wc_ecc_set_curve(&e->key, 0, curve_id) != 0 || mp_init(&e->a) != MP_OKAY || mp_init(&e->prime) != MP_OKAY || -@@ -1388,6 +1391,7 @@ void crypto_ec_deinit(struct crypto_ec* +@@ -1425,6 +1428,7 @@ void crypto_ec_deinit(struct crypto_ec* mp_clear(&e->order); mp_clear(&e->prime); mp_clear(&e->a); diff --git a/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch b/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch index d948c41b30b..0a51c84d215 100644 --- a/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch +++ b/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch @@ -14,16 +14,37 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com> --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -2395,6 +2395,8 @@ void ibss_mesh_setup_freq(struct wpa_sup - int chwidth, seg0, seg1; - u32 vht_caps = 0; - int is_24ghz; -+ int dfs_enabled = wpa_s->conf->country[0] && -+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_RADAR); +@@ -2638,7 +2638,7 @@ static int drv_supports_vht(struct wpa_s + } - freq->freq = ssid->frequency; -@@ -2484,8 +2486,11 @@ void ibss_mesh_setup_freq(struct wpa_sup +-static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode) ++static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode, bool dfs_enabled) + { + int i; + +@@ -2647,7 +2647,10 @@ static bool ibss_mesh_is_80mhz_avail(int + + chan = hw_get_channel_chan(mode, i, NULL); + if (!chan || +- chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) ++ chan->flag & HOSTAPD_CHAN_DISABLED) ++ return false; ++ ++ if (!dfs_enabled && chan->flag & (HOSTAPD_CHAN_RADAR | HOSTAPD_CHAN_NO_IR)) + return false; + } + +@@ -2774,7 +2777,7 @@ static void ibss_mesh_select_40mhz(struc + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode, + struct hostapd_freq_params *freq, +- int obss_scan) { ++ int obss_scan, bool dfs_enabled) { + int chan_idx; + struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; + int i, res; +@@ -2798,8 +2801,11 @@ static void ibss_mesh_select_40mhz(struc return; /* Check primary channel flags */ @@ -34,9 +55,9 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com> + if (!dfs_enabled) + return; - freq->channel = pri_chan->chan; - -@@ -2518,8 +2523,11 @@ void ibss_mesh_setup_freq(struct wpa_sup + #ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht40) +@@ -2825,8 +2831,11 @@ static void ibss_mesh_select_40mhz(struc return; /* Check secondary channel flags */ @@ -49,20 +70,34 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com> if (ht40 == -1) { if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS)) -@@ -2612,8 +2620,11 @@ skip_ht40: - return; - - /* Back to HT configuration if channel not usable */ -- if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) -+ if (chan->flag & HOSTAPD_CHAN_DISABLED) - return; -+ if (chan->flag & (HOSTAPD_CHAN_RADAR | HOSTAPD_CHAN_NO_IR)) -+ if (!dfs_enabled) -+ return; - } +@@ -2880,7 +2889,7 @@ static bool ibss_mesh_select_80_160mhz(s + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode, + struct hostapd_freq_params *freq, +- int ieee80211_mode, bool is_6ghz) { ++ int ieee80211_mode, bool is_6ghz, bool dfs_enabled) { + static const int bw80[] = { + 5180, 5260, 5500, 5580, 5660, 5745, 5825, + 5955, 6035, 6115, 6195, 6275, 6355, 6435, +@@ -2925,7 +2934,7 @@ static bool ibss_mesh_select_80_160mhz(s + goto skip_80mhz; - chwidth = CHANWIDTH_80MHZ; -@@ -2633,10 +2644,12 @@ skip_ht40: + /* Use 40 MHz if channel not usable */ +- if (!ibss_mesh_is_80mhz_avail(channel, mode)) ++ if (!ibss_mesh_is_80mhz_avail(channel, mode, dfs_enabled)) + goto skip_80mhz; + + chwidth = CONF_OPER_CHWIDTH_80MHZ; +@@ -2939,7 +2948,7 @@ static bool ibss_mesh_select_80_160mhz(s + if ((mode->he_capab[ieee80211_mode].phy_cap[ + HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz && +- ibss_mesh_is_80mhz_avail(channel + 16, mode)) { ++ ibss_mesh_is_80mhz_avail(channel + 16, mode, dfs_enabled)) { + for (j = 0; j < ARRAY_SIZE(bw160); j++) { + if (freq->freq == bw160[j]) { + chwidth = CONF_OPER_CHWIDTH_160MHZ; +@@ -2967,10 +2976,12 @@ static bool ibss_mesh_select_80_160mhz(s if (!chan) continue; @@ -77,4 +112,24 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com> + continue; /* Found a suitable second segment for 80+80 */ - chwidth = CHANWIDTH_80P80MHZ; + chwidth = CONF_OPER_CHWIDTH_80P80MHZ; +@@ -3025,6 +3036,7 @@ void ibss_mesh_setup_freq(struct wpa_sup + int i, obss_scan = 1; + u8 channel; + bool is_6ghz; ++ bool dfs_enabled = wpa_s->conf->country[0] && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_RADAR); + + freq->freq = ssid->frequency; + +@@ -3070,9 +3082,9 @@ void ibss_mesh_setup_freq(struct wpa_sup + freq->channel = channel; + /* Setup higher BW only for 5 GHz */ + if (mode->mode == HOSTAPD_MODE_IEEE80211A) { +- ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan); ++ ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan, dfs_enabled); + if (!ibss_mesh_select_80_160mhz(wpa_s, ssid, mode, freq, +- ieee80211_mode, is_6ghz)) ++ ieee80211_mode, is_6ghz, dfs_enabled)) + freq->he_enabled = freq->vht_enabled = false; + } + diff --git a/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch b/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch index 03a1e339a91..07b7a5971d3 100644 --- a/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch +++ b/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch @@ -28,8 +28,8 @@ Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> +#include "crypto/crypto.h" - static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) -@@ -480,9 +481,14 @@ dfs_get_valid_channel(struct hostapd_ifa + enum dfs_channel_type { +@@ -526,9 +527,14 @@ dfs_get_valid_channel(struct hostapd_ifa int num_available_chandefs; int chan_idx, chan_idx2; int sec_chan_idx_80p80 = -1; @@ -44,7 +44,7 @@ Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); *secondary_channel = 0; *oper_centr_freq_seg0_idx = 0; -@@ -502,8 +508,20 @@ dfs_get_valid_channel(struct hostapd_ifa +@@ -548,8 +554,20 @@ dfs_get_valid_channel(struct hostapd_ifa if (num_available_chandefs == 0) return NULL; @@ -64,11 +64,11 @@ Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> return NULL; + chan_idx = _rand % num_available_chandefs; - dfs_find_channel(iface, &chan, chan_idx, skip_radar); + dfs_find_channel(iface, &chan, chan_idx, type); if (!chan) { --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -9872,6 +9872,10 @@ static int nl80211_switch_channel(void * +@@ -11017,6 +11017,10 @@ static int nl80211_switch_channel(void * if (ret) goto error; diff --git a/package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch b/package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch deleted file mode 100644 index 75726a6750f..00000000000 --- a/package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch +++ /dev/null @@ -1,219 +0,0 @@ -From 90fe6429624fc48bc0e5d2d7eeecb7498708b5e3 Mon Sep 17 00:00:00 2001 -From: Daniel Golle <daniel@makrotopia.org> -Date: Wed, 18 Apr 2018 19:24:31 +0200 -Subject: [PATCH 18/18] mesh: make forwarding configurable - -Allow mesh_fwding to be specified in a mesh bss config, pass that -to the driver (only nl80211 implemented for now) and announce -forwarding capability accordingly. - -Signed-off-by: Daniel Golle <daniel@makrotopia.org> ---- - src/ap/ap_config.h | 2 ++ - src/drivers/driver.h | 2 ++ - src/drivers/driver_nl80211.c | 3 +++ - wpa_supplicant/config.c | 4 ++++ - wpa_supplicant/config.h | 9 +++++++++ - wpa_supplicant/config_file.c | 4 ++++ - wpa_supplicant/config_ssid.h | 5 +++++ - wpa_supplicant/mesh.c | 6 ++++++ - wpa_supplicant/mesh_mpm.c | 4 ++-- - wpa_supplicant/wpa_supplicant.conf | 3 +++ - 10 files changed, 40 insertions(+), 2 deletions(-) - ---- a/src/ap/ap_config.h -+++ b/src/ap/ap_config.h -@@ -51,6 +51,7 @@ struct mesh_conf { - int dot11MeshRetryTimeout; /* msec */ - int dot11MeshConfirmTimeout; /* msec */ - int dot11MeshHoldingTimeout; /* msec */ -+ int mesh_fwding; - }; - - #define MAX_STA_COUNT 2007 -@@ -696,6 +697,7 @@ struct hostapd_bss_config { - - #define MESH_ENABLED BIT(0) - int mesh; -+ int mesh_fwding; - - u8 radio_measurements[RRM_CAPABILITIES_IE_LEN]; - ---- a/src/drivers/driver.h -+++ b/src/drivers/driver.h -@@ -1584,6 +1584,7 @@ struct wpa_driver_mesh_bss_params { - #define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS 0x00000004 - #define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE 0x00000008 - #define WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD 0x00000010 -+#define WPA_DRIVER_MESH_CONF_FLAG_FORWARDING 0x00000020 - /* - * TODO: Other mesh configuration parameters would go here. - * See NL80211_MESHCONF_* for all the mesh config parameters. -@@ -1593,6 +1594,7 @@ struct wpa_driver_mesh_bss_params { - int peer_link_timeout; - int max_peer_links; - int rssi_threshold; -+ int forwarding; - u16 ht_opmode; - }; - ---- a/src/drivers/driver_nl80211.c -+++ b/src/drivers/driver_nl80211.c -@@ -10456,6 +10456,9 @@ static int nl80211_put_mesh_config(struc - if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) && - nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, - params->auto_plinks)) || -+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_FORWARDING) && -+ nla_put_u8(msg, NL80211_MESHCONF_FORWARDING, -+ params->forwarding)) || - ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) && - nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, - params->max_peer_links)) || ---- a/wpa_supplicant/config.c -+++ b/wpa_supplicant/config.c -@@ -2527,6 +2527,7 @@ static const struct parse_data ssid_fiel - #ifdef CONFIG_MESH - { INT_RANGE(mode, 0, 5) }, - { INT_RANGE(no_auto_peer, 0, 1) }, -+ { INT_RANGE(mesh_fwding, 0, 1) }, - { INT_RANGE(mesh_rssi_threshold, -255, 1) }, - #else /* CONFIG_MESH */ - { INT_RANGE(mode, 0, 4) }, -@@ -3106,6 +3107,7 @@ void wpa_config_set_network_defaults(str - ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT; - ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT; - ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT; -+ ssid->mesh_fwding = DEFAULT_MESH_FWDING; - ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD; - #endif /* CONFIG_MESH */ - #ifdef CONFIG_HT_OVERRIDES -@@ -4347,6 +4349,7 @@ struct wpa_config * wpa_config_alloc_emp - config->user_mpm = DEFAULT_USER_MPM; - config->max_peer_links = DEFAULT_MAX_PEER_LINKS; - config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY; -+ config->mesh_fwding = DEFAULT_MESH_FWDING; - config->dot11RSNASAERetransPeriod = - DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD; - config->fast_reauth = DEFAULT_FAST_REAUTH; -@@ -5047,6 +5050,7 @@ static const struct global_parse_data gl - { INT(user_mpm), 0 }, - { INT_RANGE(max_peer_links, 0, 255), 0 }, - { INT(mesh_max_inactivity), 0 }, -+ { INT_RANGE(mesh_fwding, 0, 1), 0 }, - { INT(dot11RSNASAERetransPeriod), 0 }, - #endif /* CONFIG_MESH */ - { INT(disable_scan_offload), 0 }, ---- a/wpa_supplicant/config.h -+++ b/wpa_supplicant/config.h -@@ -18,6 +18,7 @@ - #define DEFAULT_USER_MPM 1 - #define DEFAULT_MAX_PEER_LINKS 99 - #define DEFAULT_MESH_MAX_INACTIVITY 300 -+#define DEFAULT_MESH_FWDING 1 - /* - * The default dot11RSNASAERetransPeriod is defined as 40 ms in the standard, - * but use 1000 ms in practice to avoid issues on low power CPUs. -@@ -1378,6 +1379,14 @@ struct wpa_config { - int mesh_max_inactivity; - - /** -+ * mesh_fwding - Mesh network layer-2 forwarding -+ * -+ * This controls whether to enable layer-2 forwarding. -+ * By default: 1: enabled -+ */ -+ int mesh_fwding; -+ -+ /** - * dot11RSNASAERetransPeriod - Timeout to retransmit SAE Auth frame - * - * This timeout value is used in mesh STA to retransmit ---- a/wpa_supplicant/config_file.c -+++ b/wpa_supplicant/config_file.c -@@ -768,6 +768,7 @@ static void wpa_config_write_network(FIL - #endif /* IEEE8021X_EAPOL */ - INT(mode); - INT(no_auto_peer); -+ INT(mesh_fwding); - INT(frequency); - INT(enable_edmg); - INT(edmg_channel); -@@ -1449,6 +1450,9 @@ static void wpa_config_write_global(FILE - fprintf(f, "mesh_max_inactivity=%d\n", - config->mesh_max_inactivity); - -+ if (config->mesh_fwding != DEFAULT_MESH_FWDING) -+ fprintf(f, "mesh_fwding=%d\n", config->mesh_fwding); -+ - if (config->dot11RSNASAERetransPeriod != - DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD) - fprintf(f, "dot11RSNASAERetransPeriod=%d\n", ---- a/wpa_supplicant/config_ssid.h -+++ b/wpa_supplicant/config_ssid.h -@@ -546,6 +546,11 @@ struct wpa_ssid { - int dot11MeshConfirmTimeout; /* msec */ - int dot11MeshHoldingTimeout; /* msec */ - -+ /** -+ * Mesh network layer-2 forwarding -+ */ -+ int mesh_fwding; -+ - int ht; - int ht40; - ---- a/wpa_supplicant/mesh.c -+++ b/wpa_supplicant/mesh.c -@@ -140,6 +140,7 @@ static struct mesh_conf * mesh_config_cr - conf->mesh_cc_id = 0; - conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET; - conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0; -+ conf->mesh_fwding = ssid->mesh_fwding; - conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries; - conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout; - conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout; -@@ -441,6 +442,7 @@ static int wpa_supplicant_mesh_init(stru - bss->conf->start_disabled = 1; - bss->conf->mesh = MESH_ENABLED; - bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity; -+ bss->conf->mesh_fwding = wpa_s->conf->mesh_fwding; - - if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes, - wpa_s->hw.num_modes) && wpa_s->conf->country[0]) { -@@ -655,6 +657,10 @@ int wpa_supplicant_join_mesh(struct wpa_ - } - params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity; - -+ /* always explicitely set forwarding to on or off for now */ -+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_FORWARDING; -+ params->conf.forwarding = ssid->mesh_fwding; -+ - os_free(wpa_s->mesh_params); - wpa_s->mesh_params = params; - if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) { ---- a/wpa_supplicant/mesh_mpm.c -+++ b/wpa_supplicant/mesh_mpm.c -@@ -303,9 +303,9 @@ static void mesh_mpm_send_plink_action(s - info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1; - /* TODO: Add Connected to Mesh Gate/AS subfields */ - wpabuf_put_u8(buf, info); -- /* always forwarding & accepting plinks for now */ -+ /* set forwarding & always accepting plinks for now */ - wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER | -- MESH_CAP_FORWARDING); -+ (conf->mesh_fwding ? MESH_CAP_FORWARDING : 0)); - } else { /* Peer closing frame */ - /* IE: Mesh ID */ - wpabuf_put_u8(buf, WLAN_EID_MESH_ID); ---- a/wpa_supplicant/wpa_supplicant.conf -+++ b/wpa_supplicant/wpa_supplicant.conf -@@ -150,6 +150,9 @@ ap_scan=1 - # This timeout value is used in mesh STA to clean up inactive stations. - #mesh_max_inactivity=300 - -+# Enable 802.11s layer-2 routing and forwarding -+#mesh_fwding=1 -+ - # cert_in_cb - Whether to include a peer certificate dump in events - # This controls whether peer certificates for authentication server and - # its certificate chain are included in EAP peer certificate events. This is diff --git a/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch b/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch index 124fd8bdf13..edf599e3e28 100644 --- a/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch +++ b/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch @@ -1,6 +1,6 @@ --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c -@@ -4942,6 +4942,13 @@ static int add_associated_sta(struct hos +@@ -4621,6 +4621,13 @@ static int add_associated_sta(struct hos * drivers to accept the STA parameter configuration. Since this is * after a new FT-over-DS exchange, a new TK has been derived, so key * reinstallation is not a concern for this case. @@ -14,7 +14,7 @@ */ wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)", -@@ -4955,7 +4962,8 @@ static int add_associated_sta(struct hos +@@ -4634,7 +4641,8 @@ static int add_associated_sta(struct hos (!(sta->flags & WLAN_STA_AUTHORIZED) || (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) || (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) && diff --git a/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch b/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch index c7da33f0290..8dec325c985 100644 --- a/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch +++ b/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c -@@ -3431,7 +3431,7 @@ static int hostapd_change_config_freq(st +@@ -3764,7 +3764,7 @@ static int hostapd_change_config_freq(st struct hostapd_freq_params *old_params) { int channel; diff --git a/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch b/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch new file mode 100644 index 00000000000..9ff9b2398de --- /dev/null +++ b/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch @@ -0,0 +1,19 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 28 Jul 2021 05:43:29 +0200 +Subject: [PATCH] ndisc_snoop: call dl_list_del before freeing ipv6 addresses + +Fixes a segmentation fault on sta disconnect + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/ap/ndisc_snoop.c ++++ b/src/ap/ndisc_snoop.c +@@ -61,6 +61,7 @@ void sta_ip6addr_del(struct hostapd_data + dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr, + list) { + hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr); ++ dl_list_del(&ip6addr->list); + os_free(ip6addr); + } + } diff --git a/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch new file mode 100644 index 00000000000..ef2bb408fb2 --- /dev/null +++ b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch @@ -0,0 +1,275 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 28 Jul 2021 05:49:46 +0200 +Subject: [PATCH] driver_nl80211: rewrite neigh code to not depend on + libnl3-route + +Removes an unnecessary dependency and also makes the code smaller + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -16,9 +16,6 @@ + #include <net/if.h> + #include <netlink/genl/genl.h> + #include <netlink/genl/ctrl.h> +-#ifdef CONFIG_LIBNL3_ROUTE +-#include <netlink/route/neighbour.h> +-#endif /* CONFIG_LIBNL3_ROUTE */ + #include <linux/rtnetlink.h> + #include <netpacket/packet.h> + #include <linux/errqueue.h> +@@ -5783,26 +5780,29 @@ fail: + + static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr) + { +-#ifdef CONFIG_LIBNL3_ROUTE + struct wpa_driver_nl80211_data *drv = bss->drv; +- struct rtnl_neigh *rn; +- struct nl_addr *nl_addr; ++ struct ndmsg nhdr = { ++ .ndm_state = NUD_PERMANENT, ++ .ndm_ifindex = bss->ifindex, ++ .ndm_family = AF_BRIDGE, ++ }; ++ struct nl_msg *msg; + int err; + +- rn = rtnl_neigh_alloc(); +- if (!rn) ++ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE); ++ if (!msg) + return; + +- rtnl_neigh_set_family(rn, AF_BRIDGE); +- rtnl_neigh_set_ifindex(rn, bss->ifindex); +- nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN); +- if (!nl_addr) { +- rtnl_neigh_put(rn); +- return; +- } +- rtnl_neigh_set_lladdr(rn, nl_addr); ++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) ++ goto errout; ++ ++ if (nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *)addr)) ++ goto errout; ++ ++ if (nl_send_auto_complete(drv->rtnl_sk, msg) < 0) ++ goto errout; + +- err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); ++ err = nl_wait_for_ack(drv->rtnl_sk); + if (err < 0) { + wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for " + MACSTR " ifindex=%d failed: %s", MAC2STR(addr), +@@ -5812,9 +5812,8 @@ static void rtnl_neigh_delete_fdb_entry( + MACSTR, MAC2STR(addr)); + } + +- nl_addr_put(nl_addr); +- rtnl_neigh_put(rn); +-#endif /* CONFIG_LIBNL3_ROUTE */ ++errout: ++ nlmsg_free(msg); + } + + +@@ -8492,7 +8491,6 @@ static void *i802_init(struct hostapd_da + (params->num_bridge == 0 || !params->bridge[0])) + add_ifidx(drv, br_ifindex, drv->ifindex); + +-#ifdef CONFIG_LIBNL3_ROUTE + if (bss->added_if_into_bridge || bss->already_in_bridge) { + int err; + +@@ -8509,7 +8507,6 @@ static void *i802_init(struct hostapd_da + goto failed; + } + } +-#endif /* CONFIG_LIBNL3_ROUTE */ + + if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) { + wpa_printf(MSG_DEBUG, +@@ -11883,13 +11880,14 @@ static int wpa_driver_br_add_ip_neigh(vo + const u8 *ipaddr, int prefixlen, + const u8 *addr) + { +-#ifdef CONFIG_LIBNL3_ROUTE + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; +- struct rtnl_neigh *rn; +- struct nl_addr *nl_ipaddr = NULL; +- struct nl_addr *nl_lladdr = NULL; +- int family, addrsize; ++ struct ndmsg nhdr = { ++ .ndm_state = NUD_PERMANENT, ++ .ndm_ifindex = bss->br_ifindex, ++ }; ++ struct nl_msg *msg; ++ int addrsize; + int res; + + if (!ipaddr || prefixlen == 0 || !addr) +@@ -11908,85 +11906,66 @@ static int wpa_driver_br_add_ip_neigh(vo + } + + if (version == 4) { +- family = AF_INET; ++ nhdr.ndm_family = AF_INET; + addrsize = 4; + } else if (version == 6) { +- family = AF_INET6; ++ nhdr.ndm_family = AF_INET6; + addrsize = 16; + } else { + return -EINVAL; + } + +- rn = rtnl_neigh_alloc(); +- if (rn == NULL) ++ msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE); ++ if (!msg) + return -ENOMEM; + +- /* set the destination ip address for neigh */ +- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); +- if (nl_ipaddr == NULL) { +- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); +- res = -ENOMEM; ++ res = -ENOMEM; ++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) + goto errout; +- } +- nl_addr_set_prefixlen(nl_ipaddr, prefixlen); +- res = rtnl_neigh_set_dst(rn, nl_ipaddr); +- if (res) { +- wpa_printf(MSG_DEBUG, +- "nl80211: neigh set destination addr failed"); ++ ++ if (nla_put(msg, NDA_DST, addrsize, (void *)ipaddr)) + goto errout; +- } + +- /* set the corresponding lladdr for neigh */ +- nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN); +- if (nl_lladdr == NULL) { +- wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed"); +- res = -ENOMEM; ++ if (nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *)addr)) + goto errout; +- } +- rtnl_neigh_set_lladdr(rn, nl_lladdr); + +- rtnl_neigh_set_ifindex(rn, bss->br_ifindex); +- rtnl_neigh_set_state(rn, NUD_PERMANENT); ++ res = nl_send_auto_complete(drv->rtnl_sk, msg); ++ if (res < 0) ++ goto errout; + +- res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE); ++ res = nl_wait_for_ack(drv->rtnl_sk); + if (res) { + wpa_printf(MSG_DEBUG, + "nl80211: Adding bridge ip neigh failed: %s", + nl_geterror(res)); + } + errout: +- if (nl_lladdr) +- nl_addr_put(nl_lladdr); +- if (nl_ipaddr) +- nl_addr_put(nl_ipaddr); +- if (rn) +- rtnl_neigh_put(rn); ++ nlmsg_free(msg); + return res; +-#else /* CONFIG_LIBNL3_ROUTE */ +- return -1; +-#endif /* CONFIG_LIBNL3_ROUTE */ + } + + + static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version, + const u8 *ipaddr) + { +-#ifdef CONFIG_LIBNL3_ROUTE + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; +- struct rtnl_neigh *rn; +- struct nl_addr *nl_ipaddr; +- int family, addrsize; ++ struct ndmsg nhdr = { ++ .ndm_state = NUD_PERMANENT, ++ .ndm_ifindex = bss->br_ifindex, ++ }; ++ struct nl_msg *msg; ++ int addrsize; + int res; + + if (!ipaddr) + return -EINVAL; + + if (version == 4) { +- family = AF_INET; ++ nhdr.ndm_family = AF_INET; + addrsize = 4; + } else if (version == 6) { +- family = AF_INET6; ++ nhdr.ndm_family = AF_INET6; + addrsize = 16; + } else { + return -EINVAL; +@@ -12004,41 +11983,30 @@ static int wpa_driver_br_delete_ip_neigh + return -1; + } + +- rn = rtnl_neigh_alloc(); +- if (rn == NULL) ++ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE); ++ if (!msg) + return -ENOMEM; + +- /* set the destination ip address for neigh */ +- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); +- if (nl_ipaddr == NULL) { +- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); +- res = -ENOMEM; ++ res = -ENOMEM; ++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) + goto errout; +- } +- res = rtnl_neigh_set_dst(rn, nl_ipaddr); +- if (res) { +- wpa_printf(MSG_DEBUG, +- "nl80211: neigh set destination addr failed"); ++ ++ if (nla_put(msg, NDA_DST, addrsize, (void *)ipaddr)) + goto errout; +- } + +- rtnl_neigh_set_ifindex(rn, bss->br_ifindex); ++ res = nl_send_auto_complete(drv->rtnl_sk, msg); ++ if (res < 0) ++ goto errout; + +- res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); ++ res = nl_wait_for_ack(drv->rtnl_sk); + if (res) { + wpa_printf(MSG_DEBUG, + "nl80211: Deleting bridge ip neigh failed: %s", + nl_geterror(res)); + } + errout: +- if (nl_ipaddr) +- nl_addr_put(nl_ipaddr); +- if (rn) +- rtnl_neigh_put(rn); ++ nlmsg_free(msg); + return res; +-#else /* CONFIG_LIBNL3_ROUTE */ +- return -1; +-#endif /* CONFIG_LIBNL3_ROUTE */ + } + + diff --git a/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch new file mode 100644 index 00000000000..b7bf9e351e0 --- /dev/null +++ b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch @@ -0,0 +1,34 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Mon, 18 Feb 2019 12:57:11 +0100 +Subject: [PATCH] mesh: allow processing authentication frames in blocked state + +If authentication fails repeatedly e.g. because of a weak signal, the link +can end up in blocked state. If one of the nodes tries to establish a link +again before it is unblocked on the other side, it will block the link to +that other side. The same happens on the other side when it unblocks the +link. In that scenario, the link never recovers on its own. + +To fix this, allow restarting authentication even if the link is in blocked +state, but don't initiate the attempt until the blocked period is over. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/ap/ieee802_11.c ++++ b/src/ap/ieee802_11.c +@@ -3020,15 +3020,6 @@ static void handle_auth(struct hostapd_d + seq_ctrl); + return; + } +-#ifdef CONFIG_MESH +- if ((hapd->conf->mesh & MESH_ENABLED) && +- sta->plink_state == PLINK_BLOCKED) { +- wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR +- " is blocked - drop Authentication frame", +- MAC2STR(sa)); +- return; +- } +-#endif /* CONFIG_MESH */ + #ifdef CONFIG_PASN + if (auth_alg == WLAN_AUTH_PASN && + (sta->flags & WLAN_STA_ASSOC)) { diff --git a/package/network/services/hostapd/patches/050-build_fix.patch b/package/network/services/hostapd/patches/050-build_fix.patch new file mode 100644 index 00000000000..8680b07c66a --- /dev/null +++ b/package/network/services/hostapd/patches/050-build_fix.patch @@ -0,0 +1,20 @@ +--- a/hostapd/Makefile ++++ b/hostapd/Makefile +@@ -324,6 +324,7 @@ ifdef CONFIG_FILS + CFLAGS += -DCONFIG_FILS + OBJS += ../src/ap/fils_hlp.o + NEED_SHA384=y ++NEED_HMAC_SHA384_KDF=y + NEED_AES_SIV=y + ifdef CONFIG_FILS_SK_PFS + CFLAGS += -DCONFIG_FILS_SK_PFS +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -331,6 +331,7 @@ endif + ifdef CONFIG_FILS + CFLAGS += -DCONFIG_FILS + NEED_SHA384=y ++NEED_HMAC_SHA384_KDF=y + NEED_AES_SIV=y + ifdef CONFIG_FILS_SK_PFS + CFLAGS += -DCONFIG_FILS_SK_PFS diff --git a/package/network/services/hostapd/patches/100-daemonize_fix.patch b/package/network/services/hostapd/patches/100-daemonize_fix.patch deleted file mode 100644 index 687bd4082dd..00000000000 --- a/package/network/services/hostapd/patches/100-daemonize_fix.patch +++ /dev/null @@ -1,97 +0,0 @@ ---- a/src/utils/os_unix.c -+++ b/src/utils/os_unix.c -@@ -10,6 +10,7 @@ - - #include <time.h> - #include <sys/wait.h> -+#include <fcntl.h> - - #ifdef ANDROID - #include <sys/capability.h> -@@ -188,59 +189,46 @@ int os_gmtime(os_time_t t, struct os_tm - return 0; - } - -- --#ifdef __APPLE__ --#include <fcntl.h> --static int os_daemon(int nochdir, int noclose) -+int os_daemonize(const char *pid_file) - { -- int devnull; -+ int pid = 0, i, devnull; - -- if (chdir("/") < 0) -- return -1; -+#if defined(__uClinux__) || defined(__sun__) -+ return -1; -+#else /* defined(__uClinux__) || defined(__sun__) */ - -- devnull = open("/dev/null", O_RDWR); -- if (devnull < 0) -+#ifndef __APPLE__ -+ pid = fork(); -+ if (pid < 0) - return -1; -+#endif - -- if (dup2(devnull, STDIN_FILENO) < 0) { -- close(devnull); -- return -1; -+ if (pid > 0) { -+ if (pid_file) { -+ FILE *f = fopen(pid_file, "w"); -+ if (f) { -+ fprintf(f, "%u\n", pid); -+ fclose(f); -+ } -+ } -+ _exit(0); - } - -- if (dup2(devnull, STDOUT_FILENO) < 0) { -- close(devnull); -+ if (setsid() < 0) - return -1; -- } - -- if (dup2(devnull, STDERR_FILENO) < 0) { -- close(devnull); -+ if (chdir("/") < 0) - return -1; -- } -- -- return 0; --} --#else /* __APPLE__ */ --#define os_daemon daemon --#endif /* __APPLE__ */ - -- --int os_daemonize(const char *pid_file) --{ --#if defined(__uClinux__) || defined(__sun__) -- return -1; --#else /* defined(__uClinux__) || defined(__sun__) */ -- if (os_daemon(0, 0)) { -- perror("daemon"); -+ devnull = open("/dev/null", O_RDWR); -+ if (devnull < 0) - return -1; -- } - -- if (pid_file) { -- FILE *f = fopen(pid_file, "w"); -- if (f) { -- fprintf(f, "%u\n", getpid()); -- fclose(f); -- } -- } -+ for (i = 0; i <= STDERR_FILENO; i++) -+ dup2(devnull, i); -+ -+ if (devnull > 2) -+ close(devnull); - - return -0; - #endif /* defined(__uClinux__) || defined(__sun__) */ diff --git a/package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch b/package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch new file mode 100644 index 00000000000..22107944dce --- /dev/null +++ b/package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch @@ -0,0 +1,8051 @@ +From e16f200dc1d2f69efc78c7c55af0d7b410a981f9 Mon Sep 17 00:00:00 2001 +From: Glenn Strauss <gstrauss@gluelogic.com> +Date: Tue, 5 Jul 2022 02:49:50 -0400 +Subject: [PATCH 1/7] mbedtls: TLS/crypto option (initial port) + +Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> +--- + hostapd/Makefile | 91 + + hostapd/defconfig | 15 +- + src/crypto/crypto_mbedtls.c | 4043 +++++++++++++++++ + src/crypto/tls_mbedtls.c | 3313 ++++++++++++++ + .../build/build-wpa_supplicant-mbedtls.config | 24 + + tests/hwsim/example-hostapd.config | 4 + + tests/hwsim/example-wpa_supplicant.config | 4 + + wpa_supplicant/Makefile | 74 + + wpa_supplicant/defconfig | 6 +- + 9 files changed, 7571 insertions(+), 3 deletions(-) + create mode 100644 src/crypto/crypto_mbedtls.c + create mode 100644 src/crypto/tls_mbedtls.c + create mode 100644 tests/build/build-wpa_supplicant-mbedtls.config + +--- a/hostapd/Makefile ++++ b/hostapd/Makefile +@@ -745,6 +745,40 @@ endif + CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" + endif + ++ifeq ($(CONFIG_TLS), mbedtls) ++ifndef CONFIG_CRYPTO ++CONFIG_CRYPTO=mbedtls ++endif ++ifdef TLS_FUNCS ++OBJS += ../src/crypto/tls_mbedtls.o ++LIBS += -lmbedtls ++ifndef CONFIG_DPP ++LIBS += -lmbedx509 ++endif ++endif ++OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o ++HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o ++SOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o ++ifdef NEED_FIPS186_2_PRF ++OBJS += ../src/crypto/fips_prf_internal.o ++SHA1OBJS += ../src/crypto/sha1-internal.o ++endif ++ifeq ($(CONFIG_CRYPTO), mbedtls) ++ifdef CONFIG_DPP ++LIBS += -lmbedx509 ++LIBS_h += -lmbedx509 ++LIBS_n += -lmbedx509 ++LIBS_s += -lmbedx509 ++endif ++LIBS += -lmbedcrypto ++LIBS_h += -lmbedcrypto ++LIBS_n += -lmbedcrypto ++LIBS_s += -lmbedcrypto ++# XXX: create a config option? ++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ++endif ++endif ++ + ifeq ($(CONFIG_TLS), gnutls) + ifndef CONFIG_CRYPTO + # default to libgcrypt +@@ -924,9 +958,11 @@ endif + + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-wrap.o + endif + endif ++endif + ifdef NEED_AES_EAX + AESOBJS += ../src/crypto/aes-eax.o + NEED_AES_CTR=y +@@ -936,38 +972,48 @@ AESOBJS += ../src/crypto/aes-siv.o + NEED_AES_CTR=y + endif + ifdef NEED_AES_CTR ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-ctr.o + endif ++endif + ifdef NEED_AES_ENCBLOCK ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-encblock.o + endif ++endif + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-omac1.o + endif + endif + endif ++endif + ifdef NEED_AES_UNWRAP + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + NEED_AES_DEC=y + AESOBJS += ../src/crypto/aes-unwrap.o + endif + endif + endif + endif ++endif + ifdef NEED_AES_CBC + NEED_AES_DEC=y + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-cbc.o + endif + endif + endif + endif ++endif + ifdef NEED_AES_DEC + ifdef CONFIG_INTERNAL_AES + AESOBJS += ../src/crypto/aes-internal-dec.o +@@ -982,12 +1028,16 @@ ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1.o + endif + endif + endif + endif ++endif ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-prf.o ++endif + ifdef CONFIG_INTERNAL_SHA1 + SHA1OBJS += ../src/crypto/sha1-internal.o + ifdef NEED_FIPS186_2_PRF +@@ -996,16 +1046,22 @@ endif + endif + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-pbkdf2.o + endif + endif ++endif + ifdef NEED_T_PRF ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-tprf.o + endif ++endif + ifdef NEED_TLS_PRF ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-tlsprf.o + endif + endif ++endif + + ifdef NEED_SHA1 + OBJS += $(SHA1OBJS) +@@ -1015,11 +1071,13 @@ ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/md5.o + endif + endif + endif + endif ++endif + + ifdef NEED_MD5 + ifdef CONFIG_INTERNAL_MD5 +@@ -1058,56 +1116,81 @@ ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha256.o + endif + endif + endif + endif ++endif ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha256-prf.o ++endif + ifdef CONFIG_INTERNAL_SHA256 + OBJS += ../src/crypto/sha256-internal.o + endif + ifdef NEED_TLS_PRF_SHA256 ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha256-tlsprf.o + endif ++endif + ifdef NEED_TLS_PRF_SHA384 ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384-tlsprf.o + endif ++endif + ifdef NEED_HMAC_SHA256_KDF ++CFLAGS += -DCONFIG_HMAC_SHA256_KDF ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha256-kdf.o + endif ++endif + ifdef NEED_HMAC_SHA384_KDF ++CFLAGS += -DCONFIG_HMAC_SHA384_KDF ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384-kdf.o + endif ++endif + ifdef NEED_HMAC_SHA512_KDF ++CFLAGS += -DCONFIG_HMAC_SHA512_KDF ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha512-kdf.o + endif ++endif + ifdef NEED_SHA384 + CFLAGS += -DCONFIG_SHA384 + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384.o + endif + endif + endif + endif ++endif ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384-prf.o + endif ++endif + ifdef NEED_SHA512 + CFLAGS += -DCONFIG_SHA512 + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha512.o + endif + endif + endif + endif ++endif ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha512-prf.o + endif ++endif + + ifdef CONFIG_INTERNAL_SHA384 + CFLAGS += -DCONFIG_INTERNAL_SHA384 +@@ -1152,11 +1235,13 @@ HOBJS += $(SHA1OBJS) + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + HOBJS += ../src/crypto/md5.o + endif + endif + endif + endif ++endif + + ifdef CONFIG_RADIUS_SERVER + CFLAGS += -DRADIUS_SERVER +@@ -1329,7 +1414,9 @@ NOBJS += ../src/utils/trace.o + endif + + HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o ++ifneq ($(CONFIG_TLS), mbedtls) + HOBJS += ../src/crypto/aes-encblock.o ++endif + ifdef CONFIG_INTERNAL_AES + HOBJS += ../src/crypto/aes-internal.o + HOBJS += ../src/crypto/aes-internal-enc.o +@@ -1352,13 +1439,17 @@ SOBJS += ../src/common/sae.o + SOBJS += ../src/common/sae_pk.o + SOBJS += ../src/common/dragonfly.o + SOBJS += $(AESOBJS) ++ifneq ($(CONFIG_TLS), mbedtls) + SOBJS += ../src/crypto/sha256-prf.o + SOBJS += ../src/crypto/sha384-prf.o + SOBJS += ../src/crypto/sha512-prf.o ++endif + SOBJS += ../src/crypto/dh_groups.o ++ifneq ($(CONFIG_TLS), mbedtls) + SOBJS += ../src/crypto/sha256-kdf.o + SOBJS += ../src/crypto/sha384-kdf.o + SOBJS += ../src/crypto/sha512-kdf.o ++endif + + _OBJS_VAR := NOBJS + include ../src/objs.mk +--- a/hostapd/defconfig ++++ b/hostapd/defconfig +@@ -6,9 +6,21 @@ + # just setting VARIABLE=n is not disabling that variable. + # + # This file is included in Makefile, so variables like CFLAGS and LIBS can also +-# be modified from here. In most cass, these lines should use += in order not ++# be modified from here. In most cases, these lines should use += in order not + # to override previous values of the variables. + ++ ++# Uncomment following two lines and fix the paths if you have installed TLS ++# libraries in a non-default location ++#CFLAGS += -I/usr/local/openssl/include ++#LIBS += -L/usr/local/openssl/lib ++ ++# Some Red Hat versions seem to include kerberos header files from OpenSSL, but ++# the kerberos files are not in the default include path. Following line can be ++# used to fix build issues on such systems (krb5.h not found). ++#CFLAGS += -I/usr/include/kerberos ++ ++ + # Driver interface for Host AP driver + CONFIG_DRIVER_HOSTAP=y + +@@ -278,6 +290,7 @@ CONFIG_IPV6=y + # openssl = OpenSSL (default) + # gnutls = GnuTLS + # internal = Internal TLSv1 implementation (experimental) ++# mbedtls = mbed TLS + # linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) + # none = Empty template + #CONFIG_TLS=openssl +--- /dev/null ++++ b/src/crypto/crypto_mbedtls.c +@@ -0,0 +1,4043 @@ ++/* ++ * crypto wrapper functions for mbed TLS ++ * ++ * SPDX-FileCopyrightText: 2022 Glenn Strauss <gstrauss@gluelogic.com> ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include "utils/includes.h" ++#include "utils/common.h" ++ ++#include <mbedtls/version.h> ++#include <mbedtls/entropy.h> ++#include <mbedtls/ctr_drbg.h> ++#include <mbedtls/platform_util.h> /* mbedtls_platform_zeroize() */ ++#include <mbedtls/asn1.h> ++#include <mbedtls/asn1write.h> ++#include <mbedtls/aes.h> ++#include <mbedtls/md.h> ++#include <mbedtls/md5.h> ++#include <mbedtls/sha1.h> ++#include <mbedtls/sha256.h> ++#include <mbedtls/sha512.h> ++ ++#ifndef MBEDTLS_PRIVATE ++#define MBEDTLS_PRIVATE(x) x ++#endif ++ ++/* hostapd/wpa_supplicant provides forced_memzero(), ++ * but prefer mbedtls_platform_zeroize() */ ++#define forced_memzero(ptr,sz) mbedtls_platform_zeroize(ptr,sz) ++ ++#ifndef __has_attribute ++#define __has_attribute(x) 0 ++#endif ++ ++#ifndef __GNUC_PREREQ ++#define __GNUC_PREREQ(maj,min) 0 ++#endif ++ ++#ifndef __attribute_cold__ ++#if __has_attribute(cold) \ ++ || __GNUC_PREREQ(4,3) ++#define __attribute_cold__ __attribute__((__cold__)) ++#else ++#define __attribute_cold__ ++#endif ++#endif ++ ++#ifndef __attribute_noinline__ ++#if __has_attribute(noinline) \ ++ || __GNUC_PREREQ(3,1) ++#define __attribute_noinline__ __attribute__((__noinline__)) ++#else ++#define __attribute_noinline__ ++#endif ++#endif ++ ++#include "crypto.h" ++#include "aes_wrap.h" ++#include "aes.h" ++#include "md5.h" ++#include "sha1.h" ++#include "sha256.h" ++#include "sha384.h" ++#include "sha512.h" ++ ++ ++/* ++ * selective code inclusion based on preprocessor defines ++ * ++ * future: additional code could be wrapped with preprocessor checks if ++ * wpa_supplicant/Makefile and hostap/Makefile were more consistent with ++ * setting preprocessor defines for named groups of functionality ++ */ ++ ++#if defined(CONFIG_FIPS) ++#undef MBEDTLS_MD4_C /* omit md4_vector() */ ++#undef MBEDTLS_MD5_C /* omit md5_vector() hmac_md5_vector() hmac_md5() */ ++#undef MBEDTLS_DES_C /* omit des_encrypt() */ ++#undef MBEDTLS_NIST_KW_C /* omit aes_wrap() aes_unwrap() */ ++#define CRYPTO_MBEDTLS_CONFIG_FIPS ++#endif ++ ++#if !defined(CONFIG_FIPS) ++#if defined(EAP_PWD) \ ++ || defined(EAP_LEAP) || defined(EAP_LEAP_DYNAMIC) \ ++ || defined(EAP_TTLS) || defined(EAP_TTLS_DYNAMIC) \ ++ || defined(EAP_MSCHAPv2) || defined(EAP_MSCHAPv2_DYNAMIC) \ ++ || defined(EAP_SERVER_MSCHAPV2) ++#ifndef MBEDTLS_MD4_C /* (MD4 not in mbedtls 3.x) */ ++#include "md4-internal.c"/* pull in hostap local implementation */ ++#endif /* md4_vector() */ ++#else ++#undef MBEDTLS_MD4_C /* omit md4_vector() */ ++#endif ++#endif ++ ++#if !defined(CONFIG_NO_RC4) && !defined(CONFIG_NO_WPA) ++#ifndef MBEDTLS_ARC4_C /* (RC4 not in mbedtls 3.x) */ ++#include "rc4.c" /* pull in hostap local implementation */ ++#endif /* rc4_skip() */ ++#else ++#undef MBEDTLS_ARC4_C /* omit rc4_skip() */ ++#endif ++ ++#if defined(CONFIG_MACSEC) \ ++ || defined(CONFIG_NO_RADIUS) \ ++ || defined(CONFIG_IEEE80211R) \ ++ || defined(EAP_SERVER_FAST) \ ++ || defined(EAP_SERVER_TEAP) \ ++ || !defined(CONFIG_NO_WPA) ++ /* aes_wrap() aes_unwrap() */ ++#else ++#undef MBEDTLS_NIST_KW_C /* omit aes_wrap() aes_unwrap() */ ++#endif ++ ++#if !defined(CONFIG_SHA256) ++#undef MBEDTLS_SHA256_C ++#endif ++ ++#if !defined(CONFIG_SHA384) && !defined(CONFIG_SHA512) ++#undef MBEDTLS_SHA512_C ++#endif ++ ++#if defined(CONFIG_HMAC_SHA256_KDF) ++#define CRYPTO_MBEDTLS_HMAC_KDF_SHA256 ++#endif ++#if defined(CONFIG_HMAC_SHA384_KDF) ++#define CRYPTO_MBEDTLS_HMAC_KDF_SHA384 ++#endif ++#if defined(CONFIG_HMAC_SHA512_KDF) ++#define CRYPTO_MBEDTLS_HMAC_KDF_SHA512 ++#endif ++ ++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) \ ++ || defined(EAP_TEAP) || defined(EAP_TEAP_DYNAMIC) || defined(EAP_SERVER_FAST) ++#define CRYPTO_MBEDTLS_SHA1_T_PRF ++#endif ++ ++#if defined(CONFIG_DES) ++#define CRYPTO_MBEDTLS_DES_ENCRYPT ++#endif /* des_encrypt() */ ++ ++#if !defined(CONFIG_NO_PBKDF2) ++#define CRYPTO_MBEDTLS_PBKDF2_SHA1 ++#endif /* pbkdf2_sha1() */ ++ ++#if defined(EAP_IKEV2) \ ++ || defined(EAP_IKEV2_DYNAMIC) \ ++ || defined(EAP_SERVER_IKEV2) /* CONFIG_EAP_IKEV2=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_CIPHER ++#endif /* crypto_cipher_*() */ ++ ++#if defined(EAP_PWD) || defined(EAP_SERVER_PWD) /* CONFIG_EAP_PWD=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_HASH ++#endif /* crypto_hash_*() */ ++ ++#if defined(EAP_PWD) || defined(EAP_SERVER_PWD) /* CONFIG_EAP_PWD=y */ \ ++ || defined(CONFIG_SAE) /* CONFIG_SAE=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_BIGNUM ++#endif /* crypto_bignum_*() */ ++ ++#if defined(EAP_PWD) /* CONFIG_EAP_PWD=y */ \ ++ || defined(EAP_EKE) /* CONFIG_EAP_EKE=y */ \ ++ || defined(EAP_EKE_DYNAMIC) /* CONFIG_EAP_EKE=y */ \ ++ || defined(EAP_SERVER_EKE) /* CONFIG_EAP_EKE=y */ \ ++ || defined(EAP_IKEV2) /* CONFIG_EAP_IKEV2y */ \ ++ || defined(EAP_IKEV2_DYNAMIC)/* CONFIG_EAP_IKEV2=y */ \ ++ || defined(EAP_SERVER_IKEV2) /* CONFIG_EAP_IKEV2=y */ \ ++ || defined(CONFIG_SAE) /* CONFIG_SAE=y */ \ ++ || defined(CONFIG_WPS) /* CONFIG_WPS=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_DH ++#if defined(CONFIG_WPS_NFC) ++#define CRYPTO_MBEDTLS_DH5_INIT_FIXED ++#endif /* dh5_init_fixed() */ ++#endif /* crypto_dh_*() */ ++ ++#if !defined(CONFIG_NO_WPA) /* CONFIG_NO_WPA= */ ++#define CRYPTO_MBEDTLS_CRYPTO_ECDH ++#endif /* crypto_ecdh_*() */ ++ ++#if defined(CONFIG_ECC) ++#define CRYPTO_MBEDTLS_CRYPTO_BIGNUM ++#define CRYPTO_MBEDTLS_CRYPTO_EC ++#endif /* crypto_ec_*() crypto_ec_key_*() */ ++ ++#if defined(CONFIG_DPP) /* CONFIG_DPP=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_EC_DPP /* extra for DPP */ ++#define CRYPTO_MBEDTLS_CRYPTO_CSR ++#endif /* crypto_csr_*() */ ++ ++#if defined(CONFIG_DPP3) /* CONFIG_DPP3=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_HPKE ++#endif ++ ++#if defined(CONFIG_DPP2) /* CONFIG_DPP2=y */ ++#define CRYPTO_MBEDTLS_CRYPTO_PKCS7 ++#endif /* crypto_pkcs7_*() */ ++ ++#if defined(EAP_SIM) || defined(EAP_SIM_DYNAMIC) || defined(EAP_SERVER_SIM) \ ++ || defined(EAP_AKA) || defined(EAP_AKA_DYNAMIC) || defined(EAP_SERVER_AKA) \ ++ || defined(CONFIG_AP) || defined(HOSTAPD) ++/* CONFIG_EAP_SIM=y CONFIG_EAP_AKA=y CONFIG_AP=y HOSTAPD */ ++#if defined(CRYPTO_RSA_OAEP_SHA256) ++#define CRYPTO_MBEDTLS_CRYPTO_RSA ++#endif ++#endif /* crypto_rsa_*() */ ++ ++ ++static int ctr_drbg_init_state; ++static mbedtls_ctr_drbg_context ctr_drbg; ++static mbedtls_entropy_context entropy; ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_BIGNUM ++#include <mbedtls/bignum.h> ++static mbedtls_mpi mpi_sw_A; ++#endif ++ ++__attribute_cold__ ++__attribute_noinline__ ++static mbedtls_ctr_drbg_context * ctr_drbg_init(void) ++{ ++ mbedtls_ctr_drbg_init(&ctr_drbg); ++ mbedtls_entropy_init(&entropy); ++ if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, ++ NULL, 0)) { ++ wpa_printf(MSG_ERROR, "Init of random number generator failed"); ++ /* XXX: abort? */ ++ } ++ else ++ ctr_drbg_init_state = 1; ++ ++ return &ctr_drbg; ++} ++ ++__attribute_cold__ ++void crypto_unload(void) ++{ ++ if (ctr_drbg_init_state) { ++ mbedtls_ctr_drbg_free(&ctr_drbg); ++ mbedtls_entropy_free(&entropy); ++ #ifdef CRYPTO_MBEDTLS_CRYPTO_BIGNUM ++ mbedtls_mpi_free(&mpi_sw_A); ++ #endif ++ ctr_drbg_init_state = 0; ++ } ++} ++ ++/* init ctr_drbg on first use ++ * crypto_global_init() and crypto_global_deinit() are not available here ++ * (available only when CONFIG_TLS=internal, which is not CONFIG_TLS=mbedtls) */ ++mbedtls_ctr_drbg_context * crypto_mbedtls_ctr_drbg(void); /*(not in header)*/ ++inline ++mbedtls_ctr_drbg_context * crypto_mbedtls_ctr_drbg(void) ++{ ++ return ctr_drbg_init_state ? &ctr_drbg : ctr_drbg_init(); ++} ++ ++#ifdef CRYPTO_MBEDTLS_CONFIG_FIPS ++int crypto_get_random(void *buf, size_t len) ++{ ++ return mbedtls_ctr_drbg_random(crypto_mbedtls_ctr_drbg(),buf,len) ? -1 : 0; ++} ++#endif ++ ++ ++#if 1 ++ ++/* tradeoff: slightly smaller code size here at cost of slight increase ++ * in instructions and function calls at runtime versus the expanded ++ * per-message-digest code that follows in #else (~0.5 kib .text larger) */ ++ ++__attribute_noinline__ ++static int md_vector(size_t num_elem, const u8 *addr[], const size_t *len, ++ u8 *mac, mbedtls_md_type_t md_type) ++{ ++ mbedtls_md_context_t ctx; ++ mbedtls_md_init(&ctx); ++ if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0) != 0){ ++ mbedtls_md_free(&ctx); ++ return -1; ++ } ++ mbedtls_md_starts(&ctx); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_md_update(&ctx, addr[i], len[i]); ++ mbedtls_md_finish(&ctx, mac); ++ mbedtls_md_free(&ctx); ++ return 0; ++} ++ ++#ifdef MBEDTLS_SHA512_C ++int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA512); ++} ++ ++int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA384); ++} ++#endif ++ ++#ifdef MBEDTLS_SHA256_C ++int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA256); ++} ++#endif ++ ++#ifdef MBEDTLS_SHA1_C ++int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA1); ++} ++#endif ++ ++#ifdef MBEDTLS_MD5_C ++int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_MD5); ++} ++#endif ++ ++#ifdef MBEDTLS_MD4_C ++#include <mbedtls/md4.h> ++int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_MD4); ++} ++#endif ++ ++#else /* expanded per-message-digest functions */ ++ ++#ifdef MBEDTLS_SHA512_C ++#include <mbedtls/sha512.h> ++__attribute_noinline__ ++static int sha384_512_vector(size_t num_elem, const u8 *addr[], ++ const size_t *len, u8 *mac, int is384) ++{ ++ struct mbedtls_sha512_context ctx; ++ mbedtls_sha512_init(&ctx); ++ #if MBEDTLS_VERSION_MAJOR >= 3 ++ mbedtls_sha512_starts(&ctx, is384); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_sha512_update(&ctx, addr[i], len[i]); ++ mbedtls_sha512_finish(&ctx, mac); ++ #else ++ mbedtls_sha512_starts_ret(&ctx, is384); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_sha512_update_ret(&ctx, addr[i], len[i]); ++ mbedtls_sha512_finish_ret(&ctx, mac); ++ #endif ++ mbedtls_sha512_free(&ctx); ++ return 0; ++} ++ ++int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return sha384_512_vector(num_elem, addr, len, mac, 0); ++} ++ ++int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return sha384_512_vector(num_elem, addr, len, mac, 1); ++} ++#endif ++ ++#ifdef MBEDTLS_SHA256_C ++#include <mbedtls/sha256.h> ++int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ struct mbedtls_sha256_context ctx; ++ mbedtls_sha256_init(&ctx); ++ #if MBEDTLS_VERSION_MAJOR >= 3 ++ mbedtls_sha256_starts(&ctx, 0); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_sha256_update(&ctx, addr[i], len[i]); ++ mbedtls_sha256_finish(&ctx, mac); ++ #else ++ mbedtls_sha256_starts_ret(&ctx, 0); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_sha256_update_ret(&ctx, addr[i], len[i]); ++ mbedtls_sha256_finish_ret(&ctx, mac); ++ #endif ++ mbedtls_sha256_free(&ctx); ++ return 0; ++} ++#endif ++ ++#ifdef MBEDTLS_SHA1_C ++#include <mbedtls/sha1.h> ++int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ struct mbedtls_sha1_context ctx; ++ mbedtls_sha1_init(&ctx); ++ #if MBEDTLS_VERSION_MAJOR >= 3 ++ mbedtls_sha1_starts(&ctx); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_sha1_update(&ctx, addr[i], len[i]); ++ mbedtls_sha1_finish(&ctx, mac); ++ #else ++ mbedtls_sha1_starts_ret(&ctx); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_sha1_update_ret(&ctx, addr[i], len[i]); ++ mbedtls_sha1_finish_ret(&ctx, mac); ++ #endif ++ mbedtls_sha1_free(&ctx); ++ return 0; ++} ++#endif ++ ++#ifdef MBEDTLS_MD5_C ++#include <mbedtls/md5.h> ++int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ struct mbedtls_md5_context ctx; ++ mbedtls_md5_init(&ctx); ++ #if MBEDTLS_VERSION_MAJOR >= 3 ++ mbedtls_md5_starts(&ctx); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_md5_update(&ctx, addr[i], len[i]); ++ mbedtls_md5_finish(&ctx, mac); ++ #else ++ mbedtls_md5_starts_ret(&ctx); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_md5_update_ret(&ctx, addr[i], len[i]); ++ mbedtls_md5_finish_ret(&ctx, mac); ++ #endif ++ mbedtls_md5_free(&ctx); ++ return 0; ++} ++#endif ++ ++#ifdef MBEDTLS_MD4_C ++#include <mbedtls/md4.h> ++int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ struct mbedtls_md4_context ctx; ++ mbedtls_md4_init(&ctx); ++ mbedtls_md4_starts_ret(&ctx); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_md4_update_ret(&ctx, addr[i], len[i]); ++ mbedtls_md4_finish_ret(&ctx, mac); ++ mbedtls_md4_free(&ctx); ++ return 0; ++} ++#endif ++ ++#endif /* expanded per-message-digest functions */ ++ ++ ++__attribute_noinline__ ++static int hmac_vector(const u8 *key, size_t key_len, size_t num_elem, ++ const u8 *addr[], const size_t *len, u8 *mac, ++ mbedtls_md_type_t md_type) ++{ ++ mbedtls_md_context_t ctx; ++ mbedtls_md_init(&ctx); ++ if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1) != 0){ ++ mbedtls_md_free(&ctx); ++ return -1; ++ } ++ mbedtls_md_hmac_starts(&ctx, key, key_len); ++ for (size_t i = 0; i < num_elem; ++i) ++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]); ++ mbedtls_md_hmac_finish(&ctx, mac); ++ mbedtls_md_free(&ctx); ++ return 0; ++} ++ ++#ifdef MBEDTLS_SHA512_C ++int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem, ++ const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return hmac_vector(key, key_len, num_elem, addr, len, mac, ++ MBEDTLS_MD_SHA512); ++} ++ ++int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, size_t data_len, ++ u8 *mac) ++{ ++ return hmac_vector(key, key_len, 1, &data, &data_len, mac, ++ MBEDTLS_MD_SHA512); ++} ++ ++int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, ++ const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return hmac_vector(key, key_len, num_elem, addr, len, mac, ++ MBEDTLS_MD_SHA384); ++} ++ ++int hmac_sha384(const u8 *key, size_t key_len, const u8 *data, size_t data_len, ++ u8 *mac) ++{ ++ return hmac_vector(key, key_len, 1, &data, &data_len, mac, ++ MBEDTLS_MD_SHA384); ++} ++#endif ++ ++#ifdef MBEDTLS_SHA256_C ++int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, ++ const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return hmac_vector(key, key_len, num_elem, addr, len, mac, ++ MBEDTLS_MD_SHA256); ++} ++ ++int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, ++ u8 *mac) ++{ ++ return hmac_vector(key, key_len, 1, &data, &data_len, mac, ++ MBEDTLS_MD_SHA256); ++} ++#endif ++ ++#ifdef MBEDTLS_SHA1_C ++int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, ++ const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return hmac_vector(key, key_len, num_elem, addr, len, mac, ++ MBEDTLS_MD_SHA1); ++} ++ ++int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, ++ u8 *mac) ++{ ++ return hmac_vector(key, key_len, 1, &data, &data_len, mac, ++ MBEDTLS_MD_SHA1); ++} ++#endif ++ ++#ifdef MBEDTLS_MD5_C ++int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, ++ const u8 *addr[], const size_t *len, u8 *mac) ++{ ++ return hmac_vector(key, key_len, num_elem, addr, len, mac, ++ MBEDTLS_MD_MD5); ++} ++ ++int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, ++ u8 *mac) ++{ ++ return hmac_vector(key, key_len, 1, &data, &data_len, mac, ++ MBEDTLS_MD_MD5); ++} ++#endif ++ ++ ++#if defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C) ++ ++#if defined(CRYPTO_MBEDTLS_HMAC_KDF_SHA256) \ ++ || defined(CRYPTO_MBEDTLS_HMAC_KDF_SHA384) \ ++ || defined(CRYPTO_MBEDTLS_HMAC_KDF_SHA512) ++ ++#include <mbedtls/hkdf.h> ++ ++/* sha256-kdf.c sha384-kdf.c sha512-kdf.c */ ++ ++/* HMAC-SHA256 KDF (RFC 5295) and HKDF-Expand(SHA256) (RFC 5869) */ ++/* HMAC-SHA384 KDF (RFC 5295) and HKDF-Expand(SHA384) (RFC 5869) */ ++/* HMAC-SHA512 KDF (RFC 5295) and HKDF-Expand(SHA512) (RFC 5869) */ ++__attribute_noinline__ ++static int hmac_kdf_expand(const u8 *prk, size_t prk_len, ++ const char *label, const u8 *info, size_t info_len, ++ u8 *okm, size_t okm_len, mbedtls_md_type_t md_type) ++{ ++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type); ++ #ifdef MBEDTLS_HKDF_C ++ if (label == NULL) /* RFC 5869 HKDF-Expand when (label == NULL) */ ++ return mbedtls_hkdf_expand(md_info, prk, prk_len, info, ++ info_len, okm, okm_len) ? -1 : 0; ++ #endif ++ ++ const size_t mac_len = mbedtls_md_get_size(md_info); ++ /* okm_len must not exceed 255 times hash len (RFC 5869 Section 2.3) */ ++ if (okm_len > ((mac_len << 8) - mac_len)) ++ return -1; ++ ++ mbedtls_md_context_t ctx; ++ mbedtls_md_init(&ctx); ++ if (mbedtls_md_setup(&ctx, md_info, 1) != 0) { ++ mbedtls_md_free(&ctx); ++ return -1; ++ } ++ mbedtls_md_hmac_starts(&ctx, prk, prk_len); ++ ++ u8 iter = 1; ++ const u8 *addr[4] = { okm, (const u8 *)label, info, &iter }; ++ size_t len[4] = { 0, label ? os_strlen(label)+1 : 0, info_len, 1 }; ++ ++ for (; okm_len >= mac_len; okm_len -= mac_len, ++iter) { ++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i) ++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]); ++ mbedtls_md_hmac_finish(&ctx, okm); ++ mbedtls_md_hmac_reset(&ctx); ++ addr[0] = okm; ++ okm += mac_len; ++ len[0] = mac_len; /*(include digest in subsequent rounds)*/ ++ } ++ ++ if (okm_len) { ++ u8 hash[MBEDTLS_MD_MAX_SIZE]; ++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i) ++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]); ++ mbedtls_md_hmac_finish(&ctx, hash); ++ os_memcpy(okm, hash, okm_len); ++ forced_memzero(hash, mac_len); ++ } ++ ++ mbedtls_md_free(&ctx); ++ return 0; ++} ++ ++#ifdef MBEDTLS_SHA512_C ++#ifdef CRYPTO_MBEDTLS_HMAC_KDF_SHA512 ++int hmac_sha512_kdf(const u8 *secret, size_t secret_len, ++ const char *label, const u8 *seed, size_t seed_len, ++ u8 *out, size_t outlen) ++{ ++ return hmac_kdf_expand(secret, secret_len, label, seed, seed_len, ++ out, outlen, MBEDTLS_MD_SHA512); ++} ++#endif ++ ++#ifdef CRYPTO_MBEDTLS_HMAC_KDF_SHA384 ++int hmac_sha384_kdf(const u8 *secret, size_t secret_len, ++ const char *label, const u8 *seed, size_t seed_len, ++ u8 *out, size_t outlen) ++{ ++ return hmac_kdf_expand(secret, secret_len, label, seed, seed_len, ++ out, outlen, MBEDTLS_MD_SHA384); ++} ++#endif ++#endif ++ ++#ifdef MBEDTLS_SHA256_C ++#ifdef CRYPTO_MBEDTLS_HMAC_KDF_SHA256 ++int hmac_sha256_kdf(const u8 *secret, size_t secret_len, ++ const char *label, const u8 *seed, size_t seed_len, ++ u8 *out, size_t outlen) ++{ ++ return hmac_kdf_expand(secret, secret_len, label, seed, seed_len, ++ out, outlen, MBEDTLS_MD_SHA256); ++} ++#endif ++#endif ++ ++#endif /* CRYPTO_MBEDTLS_HMAC_KDF_* */ ++ ++ ++/* sha256-prf.c sha384-prf.c sha512-prf.c */ ++ ++/* hmac_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function */ ++__attribute_noinline__ ++static int hmac_prf_bits(const u8 *key, size_t key_len, const char *label, ++ const u8 *data, size_t data_len, u8 *buf, ++ size_t buf_len_bits, mbedtls_md_type_t md_type) ++{ ++ mbedtls_md_context_t ctx; ++ mbedtls_md_init(&ctx); ++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type); ++ if (mbedtls_md_setup(&ctx, md_info, 1) != 0) { ++ mbedtls_md_free(&ctx); ++ return -1; ++ } ++ mbedtls_md_hmac_starts(&ctx, key, key_len); ++ ++ u16 ctr, n_le = host_to_le16(buf_len_bits); ++ const u8 * const addr[] = { (u8 *)&ctr,(u8 *)label,data,(u8 *)&n_le }; ++ const size_t len[] = { 2, os_strlen(label), data_len, 2 }; ++ const size_t mac_len = mbedtls_md_get_size(md_info); ++ size_t buf_len = (buf_len_bits + 7) / 8; ++ for (ctr = 1; buf_len >= mac_len; buf_len -= mac_len, ++ctr) { ++ #if __BYTE_ORDER == __BIG_ENDIAN ++ ctr = host_to_le16(ctr); ++ #endif ++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i) ++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]); ++ mbedtls_md_hmac_finish(&ctx, buf); ++ mbedtls_md_hmac_reset(&ctx); ++ buf += mac_len; ++ #if __BYTE_ORDER == __BIG_ENDIAN ++ ctr = le_to_host16(ctr); ++ #endif ++ } ++ ++ if (buf_len) { ++ u8 hash[MBEDTLS_MD_MAX_SIZE]; ++ #if __BYTE_ORDER == __BIG_ENDIAN ++ ctr = host_to_le16(ctr); ++ #endif ++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i) ++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]); ++ mbedtls_md_hmac_finish(&ctx, hash); ++ os_memcpy(buf, hash, buf_len); ++ buf += buf_len; ++ forced_memzero(hash, mac_len); ++ } ++ ++ /* Mask out unused bits in last octet if it does not use all the bits */ ++ if ((buf_len_bits &= 0x7)) ++ buf[-1] &= (u8)(0xff << (8 - buf_len_bits)); ++ ++ mbedtls_md_free(&ctx); ++ return 0; ++} ++ ++#ifdef MBEDTLS_SHA512_C ++int sha512_prf(const u8 *key, size_t key_len, const char *label, ++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len) ++{ ++ return hmac_prf_bits(key, key_len, label, data, data_len, buf, ++ buf_len * 8, MBEDTLS_MD_SHA512); ++} ++ ++int sha384_prf(const u8 *key, size_t key_len, const char *label, ++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len) ++{ ++ return hmac_prf_bits(key, key_len, label, data, data_len, buf, ++ buf_len * 8, MBEDTLS_MD_SHA384); ++} ++#endif ++ ++#ifdef MBEDTLS_SHA256_C ++int sha256_prf(const u8 *key, size_t key_len, const char *label, ++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len) ++{ ++ return hmac_prf_bits(key, key_len, label, data, data_len, buf, ++ buf_len * 8, MBEDTLS_MD_SHA256); ++} ++ ++int sha256_prf_bits(const u8 *key, size_t key_len, const char *label, ++ const u8 *data, size_t data_len, u8 *buf, ++ size_t buf_len_bits) ++{ ++ return hmac_prf_bits(key, key_len, label, data, data_len, buf, ++ buf_len_bits, MBEDTLS_MD_SHA256); ++} ++#endif ++ ++#endif /* MBEDTLS_SHA256_C || MBEDTLS_SHA512_C */ ++ ++ ++#ifdef MBEDTLS_SHA1_C ++ ++/* sha1-prf.c */ ++ ++/* sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) */ ++ ++int sha1_prf(const u8 *key, size_t key_len, const char *label, ++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len) ++{ ++ /*(note: algorithm differs from hmac_prf_bits() */ ++ /*(note: smaller code size instead of expanding hmac_sha1_vector() ++ * as is done in hmac_prf_bits(); not expecting large num of loops) */ ++ u8 counter = 0; ++ const u8 *addr[] = { (u8 *)label, data, &counter }; ++ const size_t len[] = { os_strlen(label)+1, data_len, 1 }; ++ ++ for (; buf_len >= SHA1_MAC_LEN; buf_len -= SHA1_MAC_LEN, ++counter) { ++ if (hmac_sha1_vector(key, key_len, 3, addr, len, buf)) ++ return -1; ++ buf += SHA1_MAC_LEN; ++ } ++ ++ if (buf_len) { ++ u8 hash[SHA1_MAC_LEN]; ++ if (hmac_sha1_vector(key, key_len, 3, addr, len, hash)) ++ return -1; ++ os_memcpy(buf, hash, buf_len); ++ forced_memzero(hash, sizeof(hash)); ++ } ++ ++ return 0; ++} ++ ++#ifdef CRYPTO_MBEDTLS_SHA1_T_PRF ++ ++/* sha1-tprf.c */ ++ ++/* sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) (RFC 4851,Section 5.5)*/ ++ ++int sha1_t_prf(const u8 *key, size_t key_len, const char *label, ++ const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len) ++{ ++ /*(note: algorithm differs from hmac_prf_bits() and hmac_kdf() above)*/ ++ /*(note: smaller code size instead of expanding hmac_sha1_vector() ++ * as is done in hmac_prf_bits(); not expecting large num of loops) */ ++ u8 ctr; ++ u16 olen = host_to_be16(buf_len); ++ const u8 *addr[] = { buf, (u8 *)label, seed, (u8 *)&olen, &ctr }; ++ size_t len[] = { 0, os_strlen(label)+1, seed_len, 2, 1 }; ++ ++ for (ctr = 1; buf_len >= SHA1_MAC_LEN; buf_len -= SHA1_MAC_LEN, ++ctr) { ++ if (hmac_sha1_vector(key, key_len, 5, addr, len, buf)) ++ return -1; ++ addr[0] = buf; ++ buf += SHA1_MAC_LEN; ++ len[0] = SHA1_MAC_LEN; /*(include digest in subsequent rounds)*/ ++ } ++ ++ if (buf_len) { ++ u8 hash[SHA1_MAC_LEN]; ++ if (hmac_sha1_vector(key, key_len, 5, addr, len, hash)) ++ return -1; ++ os_memcpy(buf, hash, buf_len); ++ forced_memzero(hash, sizeof(hash)); ++ } ++ ++ return 0; ++} ++ ++#endif /* CRYPTO_MBEDTLS_SHA1_T_PRF */ ++ ++#endif /* MBEDTLS_SHA1_C */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_DES_ENCRYPT ++#ifdef MBEDTLS_DES_C ++#include <mbedtls/des.h> ++int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) ++{ ++ u8 pkey[8], next, tmp; ++ int i; ++ ++ /* Add parity bits to the key */ ++ next = 0; ++ for (i = 0; i < 7; i++) { ++ tmp = key[i]; ++ pkey[i] = (tmp >> i) | next | 1; ++ next = tmp << (7 - i); ++ } ++ pkey[i] = next | 1; ++ ++ mbedtls_des_context des; ++ mbedtls_des_init(&des); ++ int ret = mbedtls_des_setkey_enc(&des, pkey) ++ || mbedtls_des_crypt_ecb(&des, clear, cypher) ? -1 : 0; ++ mbedtls_des_free(&des); ++ return ret; ++} ++#else ++#include "des-internal.c"/* pull in hostap local implementation */ ++#endif ++#endif ++ ++ ++#ifdef CRYPTO_MBEDTLS_PBKDF2_SHA1 ++/* sha1-pbkdf2.c */ ++#include <mbedtls/pkcs5.h> ++int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, ++ int iterations, u8 *buf, size_t buflen) ++{ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03020200 /* mbedtls 3.2.2 */ ++ return mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, ++ (const u8 *)passphrase, os_strlen(passphrase), ++ ssid, ssid_len, iterations, 32, buf) ? -1 : 0; ++ #else ++ const mbedtls_md_info_t *md_info; ++ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); ++ if (md_info == NULL) ++ return -1; ++ mbedtls_md_context_t ctx; ++ mbedtls_md_init(&ctx); ++ int ret = mbedtls_md_setup(&ctx, md_info, 1) ++ || mbedtls_pkcs5_pbkdf2_hmac(&ctx, ++ (const u8 *)passphrase, os_strlen(passphrase), ++ ssid, ssid_len, iterations, 32, buf) ? -1 : 0; ++ mbedtls_md_free(&ctx); ++ return ret; ++ #endif ++} ++#endif ++ ++ ++/*#include "aes.h"*/ /* prototypes also included in "crypto.h" */ ++ ++static void *aes_crypt_init_mode(const u8 *key, size_t len, int mode) ++{ ++ mbedtls_aes_context *aes = os_malloc(sizeof(*aes)); ++ if (!aes) ++ return NULL; ++ ++ mbedtls_aes_init(aes); ++ if ((mode == MBEDTLS_AES_ENCRYPT ++ ? mbedtls_aes_setkey_enc(aes, key, len * 8) ++ : mbedtls_aes_setkey_dec(aes, key, len * 8)) == 0) ++ return aes; ++ ++ mbedtls_aes_free(aes); ++ os_free(aes); ++ return NULL; ++} ++ ++void *aes_encrypt_init(const u8 *key, size_t len) ++{ ++ return aes_crypt_init_mode(key, len, MBEDTLS_AES_ENCRYPT); ++} ++ ++int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) ++{ ++ return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, plain, crypt); ++} ++ ++void aes_encrypt_deinit(void *ctx) ++{ ++ mbedtls_aes_free(ctx); ++ os_free(ctx); ++} ++ ++void *aes_decrypt_init(const u8 *key, size_t len) ++{ ++ return aes_crypt_init_mode(key, len, MBEDTLS_AES_DECRYPT); ++} ++ ++int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) ++{ ++ return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_DECRYPT, crypt, plain); ++} ++ ++void aes_decrypt_deinit(void *ctx) ++{ ++ mbedtls_aes_free(ctx); ++ os_free(ctx); ++} ++ ++ ++#include "aes_wrap.h" ++ ++ ++#ifdef MBEDTLS_NIST_KW_C ++ ++#include <mbedtls/nist_kw.h> ++ ++/* aes-wrap.c */ ++int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) ++{ ++ mbedtls_nist_kw_context ctx; ++ mbedtls_nist_kw_init(&ctx); ++ size_t olen; ++ int ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, ++ kek, kek_len*8, 1) ++ || mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, plain, n*8, ++ cipher, &olen, (n+1)*8) ? -1 : 0; ++ mbedtls_nist_kw_free(&ctx); ++ return ret; ++} ++ ++/* aes-unwrap.c */ ++int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) ++{ ++ mbedtls_nist_kw_context ctx; ++ mbedtls_nist_kw_init(&ctx); ++ size_t olen; ++ int ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, ++ kek, kek_len*8, 0) ++ || mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW, cipher, ++ (n+1)*8, plain, &olen, n*8) ? -1 : 0; ++ mbedtls_nist_kw_free(&ctx); ++ return ret; ++} ++ ++#else ++ ++#ifndef CRYPTO_MBEDTLS_CONFIG_FIPS ++#include "aes-wrap.c" /* pull in hostap local implementation */ ++#include "aes-unwrap.c" /* pull in hostap local implementation */ ++#endif ++ ++#endif /* MBEDTLS_NIST_KW_C */ ++ ++ ++#ifdef MBEDTLS_CMAC_C ++ ++/* aes-omac1.c */ ++ ++#include <mbedtls/cmac.h> ++ ++int omac1_aes_vector( ++ const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], ++ const size_t *len, u8 *mac) ++{ ++ mbedtls_cipher_type_t cipher_type; ++ switch (key_len) { ++ case 16: cipher_type = MBEDTLS_CIPHER_AES_128_ECB; break; ++ case 24: cipher_type = MBEDTLS_CIPHER_AES_192_ECB; break; ++ case 32: cipher_type = MBEDTLS_CIPHER_AES_256_ECB; break; ++ default: return -1; ++ } ++ const mbedtls_cipher_info_t *cipher_info; ++ cipher_info = mbedtls_cipher_info_from_type(cipher_type); ++ if (cipher_info == NULL) ++ return -1; ++ ++ mbedtls_cipher_context_t ctx; ++ mbedtls_cipher_init(&ctx); ++ int ret = -1; ++ if (mbedtls_cipher_setup(&ctx, cipher_info) == 0 ++ && mbedtls_cipher_cmac_starts(&ctx, key, key_len*8) == 0) { ++ ret = 0; ++ for (size_t i = 0; i < num_elem && ret == 0; ++i) ++ ret = mbedtls_cipher_cmac_update(&ctx, addr[i], len[i]); ++ } ++ if (ret == 0) ++ ret = mbedtls_cipher_cmac_finish(&ctx, mac); ++ mbedtls_cipher_free(&ctx); ++ return ret ? -1 : 0; ++} ++ ++int omac1_aes_128_vector(const u8 *key, size_t num_elem, ++ const u8 *addr[], const size_t *len, ++ u8 *mac) ++{ ++ return omac1_aes_vector(key, 16, num_elem, addr, len, mac); ++} ++ ++int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) ++{ ++ return omac1_aes_vector(key, 16, 1, &data, &data_len, mac); ++} ++ ++int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) ++{ ++ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac); ++} ++ ++#else ++ ++#include "aes-omac1.c" /* pull in hostap local implementation */ ++ ++#ifndef MBEDTLS_AES_BLOCK_SIZE ++#define MBEDTLS_AES_BLOCK_SIZE 16 ++#endif ++ ++#endif /* MBEDTLS_CMAC_C */ ++ ++ ++/* These interfaces can be inefficient when used in loops, as the overhead of ++ * initialization each call is large for each block input (e.g. 16 bytes) */ ++ ++ ++/* aes-encblock.c */ ++int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) ++{ ++ mbedtls_aes_context aes; ++ mbedtls_aes_init(&aes); ++ int ret = mbedtls_aes_setkey_enc(&aes, key, 128) ++ || mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, in, out) ++ ? -1 ++ : 0; ++ mbedtls_aes_free(&aes); ++ return ret; ++} ++ ++ ++/* aes-ctr.c */ ++int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce, ++ u8 *data, size_t data_len) ++{ ++ unsigned char counter[MBEDTLS_AES_BLOCK_SIZE]; ++ unsigned char stream_block[MBEDTLS_AES_BLOCK_SIZE]; ++ os_memcpy(counter, nonce, MBEDTLS_AES_BLOCK_SIZE);/*(must be writable)*/ ++ ++ mbedtls_aes_context ctx; ++ mbedtls_aes_init(&ctx); ++ size_t nc_off = 0; ++ int ret = mbedtls_aes_setkey_enc(&ctx, key, key_len*8) ++ || mbedtls_aes_crypt_ctr(&ctx, data_len, &nc_off, ++ counter, stream_block, ++ data, data) ? -1 : 0; ++ forced_memzero(stream_block, sizeof(stream_block)); ++ mbedtls_aes_free(&ctx); ++ return ret; ++} ++ ++int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, ++ u8 *data, size_t data_len) ++{ ++ return aes_ctr_encrypt(key, 16, nonce, data, data_len); ++} ++ ++ ++/* aes-cbc.c */ ++static int aes_128_cbc_oper(const u8 *key, const u8 *iv, ++ u8 *data, size_t data_len, int mode) ++{ ++ unsigned char ivec[MBEDTLS_AES_BLOCK_SIZE]; ++ os_memcpy(ivec, iv, MBEDTLS_AES_BLOCK_SIZE); /*(must be writable)*/ ++ ++ mbedtls_aes_context ctx; ++ mbedtls_aes_init(&ctx); ++ int ret = (mode == MBEDTLS_AES_ENCRYPT ++ ? mbedtls_aes_setkey_enc(&ctx, key, 128) ++ : mbedtls_aes_setkey_dec(&ctx, key, 128)) ++ || mbedtls_aes_crypt_cbc(&ctx, mode, data_len, ivec, data, data); ++ mbedtls_aes_free(&ctx); ++ return ret ? -1 : 0; ++} ++ ++int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) ++{ ++ return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_ENCRYPT); ++} ++ ++int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) ++{ ++ return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_DECRYPT); ++} ++ ++ ++/* ++ * Much of the following is documented in crypto.h as for CONFIG_TLS=internal ++ * but such comments are not accurate: ++ * ++ * "This function is only used with internal TLSv1 implementation ++ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need ++ * to implement this." ++ */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_CIPHER ++ ++#include <mbedtls/cipher.h> ++ ++struct crypto_cipher ++{ ++ mbedtls_cipher_context_t ctx_enc; ++ mbedtls_cipher_context_t ctx_dec; ++}; ++ ++struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, ++ const u8 *iv, const u8 *key, ++ size_t key_len) ++{ ++ /* IKEv2 src/eap_common/ikev2_common.c:ikev2_{encr,decr}_encrypt() ++ * uses one of CRYPTO_CIPHER_ALG_AES or CRYPTO_CIPHER_ALG_3DES */ ++ ++ mbedtls_cipher_type_t cipher_type; ++ size_t iv_len; ++ switch (alg) { ++ #ifdef MBEDTLS_ARC4_C ++ #if 0 ++ case CRYPTO_CIPHER_ALG_RC4: ++ cipher_type = MBEDTLS_CIPHER_ARC4_128; ++ iv_len = 0; ++ break; ++ #endif ++ #endif ++ #ifdef MBEDTLS_AES_C ++ case CRYPTO_CIPHER_ALG_AES: ++ if (key_len == 16) cipher_type = MBEDTLS_CIPHER_AES_128_CTR; ++ if (key_len == 24) cipher_type = MBEDTLS_CIPHER_AES_192_CTR; ++ if (key_len == 32) cipher_type = MBEDTLS_CIPHER_AES_256_CTR; ++ iv_len = 16; ++ break; ++ #endif ++ #ifdef MBEDTLS_DES_C ++ case CRYPTO_CIPHER_ALG_3DES: ++ cipher_type = MBEDTLS_CIPHER_DES_EDE3_CBC; ++ iv_len = 8; ++ break; ++ #if 0 ++ case CRYPTO_CIPHER_ALG_DES: ++ cipher_type = MBEDTLS_CIPHER_DES_CBC; ++ iv_len = 8; ++ break; ++ #endif ++ #endif ++ default: ++ return NULL; ++ } ++ ++ const mbedtls_cipher_info_t *cipher_info; ++ cipher_info = mbedtls_cipher_info_from_type(cipher_type); ++ if (cipher_info == NULL) ++ return NULL; ++ ++ key_len *= 8; /* key_bitlen */ ++ #if 0 /*(were key_bitlen not already available)*/ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03010000 /* mbedtls 3.1.0 */ ++ key_len = mbedtls_cipher_info_get_key_bitlen(cipher_info); ++ #else ++ key_len = cipher_info->MBEDTLS_PRIVATE(key_bitlen); ++ #endif ++ #endif ++ ++ #if 0 /*(were iv_len not known above, would need MBEDTLS_PRIVATE(iv_size))*/ ++ iv_len = cipher_info->MBEDTLS_PRIVATE(iv_size); ++ #endif ++ ++ struct crypto_cipher *ctx = os_malloc(sizeof(*ctx)); ++ if (!ctx) ++ return NULL; ++ ++ mbedtls_cipher_init(&ctx->ctx_enc); ++ mbedtls_cipher_init(&ctx->ctx_dec); ++ if ( mbedtls_cipher_setup(&ctx->ctx_enc,cipher_info) == 0 ++ && mbedtls_cipher_setup(&ctx->ctx_dec,cipher_info) == 0 ++ && mbedtls_cipher_setkey(&ctx->ctx_enc,key,key_len,MBEDTLS_ENCRYPT) == 0 ++ && mbedtls_cipher_setkey(&ctx->ctx_dec,key,key_len,MBEDTLS_DECRYPT) == 0 ++ && mbedtls_cipher_set_iv(&ctx->ctx_enc,iv,iv_len) == 0 ++ && mbedtls_cipher_set_iv(&ctx->ctx_dec,iv,iv_len) == 0 ++ && mbedtls_cipher_reset(&ctx->ctx_enc) == 0 ++ && mbedtls_cipher_reset(&ctx->ctx_dec) == 0) { ++ return ctx; ++ } ++ ++ mbedtls_cipher_free(&ctx->ctx_enc); ++ mbedtls_cipher_free(&ctx->ctx_dec); ++ os_free(ctx); ++ return NULL; ++} ++ ++int crypto_cipher_encrypt(struct crypto_cipher *ctx, ++ const u8 *plain, u8 *crypt, size_t len) ++{ ++ size_t olen = 0; /*(poor interface above; unknown size of u8 *crypt)*/ ++ return (mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen) ++ || mbedtls_cipher_finish(&ctx->ctx_enc, crypt + olen, &olen)) ? -1 : 0; ++} ++ ++int crypto_cipher_decrypt(struct crypto_cipher *ctx, ++ const u8 *crypt, u8 *plain, size_t len) ++{ ++ size_t olen = 0; /*(poor interface above; unknown size of u8 *plain)*/ ++ return (mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen) ++ || mbedtls_cipher_finish(&ctx->ctx_dec, plain + olen, &olen)) ? -1 : 0; ++} ++ ++void crypto_cipher_deinit(struct crypto_cipher *ctx) ++{ ++ mbedtls_cipher_free(&ctx->ctx_enc); ++ mbedtls_cipher_free(&ctx->ctx_dec); ++ os_free(ctx); ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_CIPHER */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_HASH ++ ++struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, ++ size_t key_len) ++{ ++ mbedtls_md_type_t md_type; ++ int is_hmac = 0; ++ ++ switch (alg) { ++ #ifdef MBEDTLS_MD5_C ++ case CRYPTO_HASH_ALG_MD5: ++ md_type = MBEDTLS_MD_MD5; ++ break; ++ #endif ++ #ifdef MBEDTLS_SHA1_C ++ case CRYPTO_HASH_ALG_SHA1: ++ md_type = MBEDTLS_MD_SHA1; ++ break; ++ #endif ++ #ifdef MBEDTLS_MD5_C ++ case CRYPTO_HASH_ALG_HMAC_MD5: ++ md_type = MBEDTLS_MD_MD5; ++ is_hmac = 1; ++ break; ++ #endif ++ #ifdef MBEDTLS_SHA1_C ++ case CRYPTO_HASH_ALG_HMAC_SHA1: ++ md_type = MBEDTLS_MD_SHA1; ++ is_hmac = 1; ++ break; ++ #endif ++ #ifdef MBEDTLS_SHA256_C ++ case CRYPTO_HASH_ALG_SHA256: ++ md_type = MBEDTLS_MD_SHA256; ++ break; ++ case CRYPTO_HASH_ALG_HMAC_SHA256: ++ md_type = MBEDTLS_MD_SHA256; ++ is_hmac = 1; ++ break; ++ #endif ++ #ifdef MBEDTLS_SHA512_C ++ case CRYPTO_HASH_ALG_SHA384: ++ md_type = MBEDTLS_MD_SHA384; ++ break; ++ case CRYPTO_HASH_ALG_SHA512: ++ md_type = MBEDTLS_MD_SHA512; ++ break; ++ #endif ++ default: ++ return NULL; ++ } ++ ++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type); ++ if (!md_info) ++ return NULL; ++ ++ mbedtls_md_context_t *mctx = os_malloc(sizeof(*mctx)); ++ if (mctx == NULL) ++ return NULL; ++ ++ mbedtls_md_init(mctx); ++ if (mbedtls_md_setup(mctx, md_info, is_hmac) != 0) { ++ os_free(mctx); ++ return NULL; ++ } ++ ++ if (is_hmac) ++ mbedtls_md_hmac_starts(mctx, key, key_len); ++ else ++ mbedtls_md_starts(mctx); ++ return (struct crypto_hash *)((uintptr_t)mctx | is_hmac); ++} ++ ++void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) ++{ ++ mbedtls_md_context_t *mctx = (mbedtls_md_context_t*)((uintptr_t)ctx & ~1uL); ++ #if 0 ++ /*(mbedtls_md_hmac_update() and mbedtls_md_update() ++ * make same modifications under the hood in mbedtls)*/ ++ if ((uintptr_t)ctx & 1uL) ++ mbedtls_md_hmac_update(mctx, data, len); ++ else ++ #endif ++ mbedtls_md_update(mctx, data, len); ++} ++ ++int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) ++{ ++ mbedtls_md_context_t *mctx = (mbedtls_md_context_t*)((uintptr_t)ctx & ~1uL); ++ if (mac != NULL && len != NULL) { /*(NULL if caller just freeing context)*/ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */ ++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_ctx(mctx); ++ #else ++ const mbedtls_md_info_t *md_info = mctx->MBEDTLS_PRIVATE(md_info); ++ #endif ++ size_t maclen = mbedtls_md_get_size(md_info); ++ if (*len < maclen) { ++ *len = maclen; ++ /*(note: ctx not freed; can call again with larger *len)*/ ++ return -1; ++ } ++ *len = maclen; ++ if ((uintptr_t)ctx & 1uL) ++ mbedtls_md_hmac_finish(mctx, mac); ++ else ++ mbedtls_md_finish(mctx, mac); ++ } ++ mbedtls_md_free(mctx); ++ os_free(mctx); ++ return 0; ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_HASH */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_BIGNUM ++ ++#include <mbedtls/bignum.h> ++ ++/* crypto.h bignum interfaces */ ++ ++struct crypto_bignum *crypto_bignum_init(void) ++{ ++ mbedtls_mpi *bn = os_malloc(sizeof(*bn)); ++ if (bn) ++ mbedtls_mpi_init(bn); ++ return (struct crypto_bignum *)bn; ++} ++ ++struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len) ++{ ++ mbedtls_mpi *bn = os_malloc(sizeof(*bn)); ++ if (bn) { ++ mbedtls_mpi_init(bn); ++ if (mbedtls_mpi_read_binary(bn, buf, len) == 0) ++ return (struct crypto_bignum *)bn; ++ } ++ ++ os_free(bn); ++ return NULL; ++} ++ ++struct crypto_bignum *crypto_bignum_init_uint(unsigned int val) ++{ ++ #if 0 /*(hostap use of this interface passes int, not uint)*/ ++ val = host_to_be32(val); ++ return crypto_bignum_init_set((const u8 *)&val, sizeof(val)); ++ #else ++ mbedtls_mpi *bn = os_malloc(sizeof(*bn)); ++ if (bn) { ++ mbedtls_mpi_init(bn); ++ if (mbedtls_mpi_lset(bn, (int)val) == 0) ++ return (struct crypto_bignum *)bn; ++ } ++ ++ os_free(bn); ++ return NULL; ++ #endif ++} ++ ++void crypto_bignum_deinit(struct crypto_bignum *n, int clear) ++{ ++ mbedtls_mpi_free((mbedtls_mpi *)n); ++ os_free(n); ++} ++ ++int crypto_bignum_to_bin(const struct crypto_bignum *a, ++ u8 *buf, size_t buflen, size_t padlen) ++{ ++ size_t n = mbedtls_mpi_size((mbedtls_mpi *)a); ++ if (n < padlen) ++ n = padlen; ++ return n > buflen || mbedtls_mpi_write_binary((mbedtls_mpi *)a, buf, n) ++ ? -1 ++ : (int)(n); ++} ++ ++int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m) ++{ ++ /*assert(r != m);*//* r must not be same as m for mbedtls_mpi_random()*/ ++ #if MBEDTLS_VERSION_NUMBER >= 0x021B0000 /* mbedtls 2.27.0 */ ++ return mbedtls_mpi_random((mbedtls_mpi *)r, 0, (mbedtls_mpi *)m, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) ? -1 : 0; ++ #else ++ /* (needed by EAP_PWD, SAE, DPP) */ ++ wpa_printf(MSG_ERROR, ++ "mbedtls 2.27.0 or later required for mbedtls_mpi_random()"); ++ return -1; ++ #endif ++} ++ ++int crypto_bignum_add(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ struct crypto_bignum *c) ++{ ++ return mbedtls_mpi_add_mpi((mbedtls_mpi *)c, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ? -1 : 0; ++} ++ ++int crypto_bignum_mod(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ struct crypto_bignum *c) ++{ ++ return mbedtls_mpi_mod_mpi((mbedtls_mpi *)c, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ? -1 : 0; ++} ++ ++int crypto_bignum_exptmod(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ const struct crypto_bignum *c, ++ struct crypto_bignum *d) ++{ ++ /* (check if input params match d; d is the result) */ ++ /* (a == d) is ok in current mbedtls implementation */ ++ if (b == d || c == d) { /*(not ok; store result in intermediate)*/ ++ mbedtls_mpi R; ++ mbedtls_mpi_init(&R); ++ int rc = mbedtls_mpi_exp_mod(&R, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b, ++ (const mbedtls_mpi *)c, ++ NULL) ++ || mbedtls_mpi_copy((mbedtls_mpi *)d, &R) ? -1 : 0; ++ mbedtls_mpi_free(&R); ++ return rc; ++ } ++ else { ++ return mbedtls_mpi_exp_mod((mbedtls_mpi *)d, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b, ++ (const mbedtls_mpi *)c, ++ NULL) ? -1 : 0; ++ } ++} ++ ++int crypto_bignum_inverse(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ struct crypto_bignum *c) ++{ ++ return mbedtls_mpi_inv_mod((mbedtls_mpi *)c, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ? -1 : 0; ++} ++ ++int crypto_bignum_sub(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ struct crypto_bignum *c) ++{ ++ return mbedtls_mpi_sub_mpi((mbedtls_mpi *)c, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ? -1 : 0; ++} ++ ++int crypto_bignum_div(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ struct crypto_bignum *c) ++{ ++ /*(most current use of this crypto.h interface has a == c (result), ++ * so store result in an intermediate to avoid overwritten input)*/ ++ mbedtls_mpi R; ++ mbedtls_mpi_init(&R); ++ int rc = mbedtls_mpi_div_mpi(&R, NULL, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ++ || mbedtls_mpi_copy((mbedtls_mpi *)c, &R) ? -1 : 0; ++ mbedtls_mpi_free(&R); ++ return rc; ++} ++ ++int crypto_bignum_addmod(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ const struct crypto_bignum *c, ++ struct crypto_bignum *d) ++{ ++ return mbedtls_mpi_add_mpi((mbedtls_mpi *)d, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ++ || mbedtls_mpi_mod_mpi((mbedtls_mpi *)d, ++ (mbedtls_mpi *)d, ++ (const mbedtls_mpi *)c) ? -1 : 0; ++} ++ ++int crypto_bignum_mulmod(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ const struct crypto_bignum *c, ++ struct crypto_bignum *d) ++{ ++ return mbedtls_mpi_mul_mpi((mbedtls_mpi *)d, ++ (const mbedtls_mpi *)a, ++ (const mbedtls_mpi *)b) ++ || mbedtls_mpi_mod_mpi((mbedtls_mpi *)d, ++ (mbedtls_mpi *)d, ++ (const mbedtls_mpi *)c) ? -1 : 0; ++} ++ ++int crypto_bignum_sqrmod(const struct crypto_bignum *a, ++ const struct crypto_bignum *b, ++ struct crypto_bignum *c) ++{ ++ #if 1 ++ return crypto_bignum_mulmod(a, a, b, c); ++ #else ++ mbedtls_mpi bn; ++ mbedtls_mpi_init(&bn); ++ if (mbedtls_mpi_lset(&bn, 2)) /* alt?: mbedtls_mpi_set_bit(&bn, 1) */ ++ return -1; ++ int ret = mbedtls_mpi_exp_mod((mbedtls_mpi *)c, ++ (const mbedtls_mpi *)a, &bn, ++ (const mbedtls_mpi *)b, NULL) ? -1 : 0; ++ mbedtls_mpi_free(&bn); ++ return ret; ++ #endif ++} ++ ++int crypto_bignum_rshift(const struct crypto_bignum *a, int n, ++ struct crypto_bignum *r) ++{ ++ return mbedtls_mpi_copy((mbedtls_mpi *)r, (const mbedtls_mpi *)a) ++ || mbedtls_mpi_shift_r((mbedtls_mpi *)r, n) ? -1 : 0; ++} ++ ++int crypto_bignum_cmp(const struct crypto_bignum *a, ++ const struct crypto_bignum *b) ++{ ++ return mbedtls_mpi_cmp_mpi((const mbedtls_mpi *)a, (const mbedtls_mpi *)b); ++} ++ ++int crypto_bignum_is_zero(const struct crypto_bignum *a) ++{ ++ /* XXX: src/common/sae.c:sswu() contains comment: ++ * "TODO: Make sure crypto_bignum_is_zero() is constant time" ++ * Note: mbedtls_mpi_cmp_int() *is not* constant time */ ++ return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 0) == 0); ++} ++ ++int crypto_bignum_is_one(const struct crypto_bignum *a) ++{ ++ return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 1) == 0); ++} ++ ++int crypto_bignum_is_odd(const struct crypto_bignum *a) ++{ ++ return mbedtls_mpi_get_bit((const mbedtls_mpi *)a, 0); ++} ++ ++#include "utils/const_time.h" ++int crypto_bignum_legendre(const struct crypto_bignum *a, ++ const struct crypto_bignum *p) ++{ ++ /* Security Note: ++ * mbedtls_mpi_exp_mod() is not documented to run in constant time, ++ * though mbedtls/library/bignum.c uses constant_time_internal.h funcs. ++ * Compare to crypto_openssl.c:crypto_bignum_legendre() ++ * which uses openssl BN_mod_exp_mont_consttime() ++ * mbedtls/library/ecp.c has further countermeasures to timing attacks, ++ * (but ecp.c funcs are not used here) */ ++ ++ mbedtls_mpi exp, tmp; ++ mbedtls_mpi_init(&exp); ++ mbedtls_mpi_init(&tmp); ++ ++ /* exp = (p-1) / 2 */ ++ int res; ++ if (mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *)p, 1) == 0 ++ && mbedtls_mpi_shift_r(&exp, 1) == 0 ++ && mbedtls_mpi_exp_mod(&tmp, (const mbedtls_mpi *)a, &exp, ++ (const mbedtls_mpi *)p, NULL) == 0) { ++ /*(modified from crypto_openssl.c:crypto_bignum_legendre())*/ ++ /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need ++ * to use constant time selection to avoid branches here. */ ++ unsigned int mask; ++ res = -1; ++ mask = const_time_eq((mbedtls_mpi_cmp_int(&tmp, 1) == 0), 1); ++ res = const_time_select_int(mask, 1, res); ++ mask = const_time_eq((mbedtls_mpi_cmp_int(&tmp, 0) == 0), 1); ++ res = const_time_select_int(mask, 0, res); ++ } else { ++ res = -2; ++ } ++ ++ mbedtls_mpi_free(&tmp); ++ mbedtls_mpi_free(&exp); ++ return res; ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_BIGNUM */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_DH ++ ++/* crypto_internal-modexp.c */ ++ ++#include <mbedtls/bignum.h> ++#include <mbedtls/dhm.h> ++ ++#if 0 /* crypto_dh_init() and crypto_dh_derive_secret() prefer to use mbedtls */ ++int crypto_mod_exp(const u8 *base, size_t base_len, ++ const u8 *power, size_t power_len, ++ const u8 *modulus, size_t modulus_len, ++ u8 *result, size_t *result_len) ++{ ++ mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result; ++ mbedtls_mpi_init(&bn_base); ++ mbedtls_mpi_init(&bn_exp); ++ mbedtls_mpi_init(&bn_modulus); ++ mbedtls_mpi_init(&bn_result); ++ ++ size_t len; ++ int ret = mbedtls_mpi_read_binary(&bn_base, base, base_len) ++ || mbedtls_mpi_read_binary(&bn_exp, power, power_len) ++ || mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len) ++ || mbedtls_mpi_exp_mod(&bn_result,&bn_base,&bn_exp,&bn_modulus,NULL) ++ || (len = mbedtls_mpi_size(&bn_result)) > *result_len ++ || mbedtls_mpi_write_binary(&bn_result, result, (*result_len = len)) ++ ? -1 ++ : 0; ++ ++ mbedtls_mpi_free(&bn_base); ++ mbedtls_mpi_free(&bn_exp); ++ mbedtls_mpi_free(&bn_modulus); ++ mbedtls_mpi_free(&bn_result); ++ return ret; ++} ++#endif ++ ++static int crypto_mbedtls_dh_set_bin_pg(mbedtls_dhm_context *ctx, u8 generator, ++ const u8 *prime, size_t prime_len) ++{ ++ /*(could set these directly in MBEDTLS_PRIVATE members)*/ ++ mbedtls_mpi P, G; ++ mbedtls_mpi_init(&P); ++ mbedtls_mpi_init(&G); ++ int ret = mbedtls_mpi_lset(&G, generator) ++ || mbedtls_mpi_read_binary(&P, prime, prime_len) ++ || mbedtls_dhm_set_group(ctx, &P, &G); ++ mbedtls_mpi_free(&P); ++ mbedtls_mpi_free(&G); ++ return ret; ++} ++ ++__attribute_noinline__ ++static int crypto_mbedtls_dh_init_public(mbedtls_dhm_context *ctx, u8 generator, ++ const u8 *prime, size_t prime_len, ++ u8 *privkey, u8 *pubkey) ++{ ++ if (crypto_mbedtls_dh_set_bin_pg(ctx, generator, prime, prime_len) ++ || mbedtls_dhm_make_public(ctx, (int)prime_len, pubkey, prime_len, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg())) ++ return -1; ++ ++ /*(enable later when upstream mbedtls interface changes require)*/ ++ #if 0 && MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ mbedtls_mpi X; ++ mbedtls_mpi_init(&X); ++ int ret = mbedtls_dhm_get_value(ctx, MBEDTLS_DHM_PARAM_X, &X) ++ || mbedtls_mpi_write_binary(&X, privkey, prime_len) ? -1 : 0; ++ mbedtls_mpi_free(&X); ++ return ret; ++ #else ++ return mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(X), ++ privkey, prime_len) ? -1 : 0; ++ #endif ++} ++ ++int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, ++ u8 *pubkey) ++{ ++ #if 0 /*(crypto_dh_init() duplicated (and identical) in crypto_*.c modules)*/ ++ size_t pubkey_len, pad; ++ ++ if (os_get_random(privkey, prime_len) < 0) ++ return -1; ++ if (os_memcmp(privkey, prime, prime_len) > 0) { ++ /* Make sure private value is smaller than prime */ ++ privkey[0] = 0; ++ } ++ ++ pubkey_len = prime_len; ++ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len, ++ pubkey, &pubkey_len) < 0) ++ return -1; ++ if (pubkey_len < prime_len) { ++ pad = prime_len - pubkey_len; ++ os_memmove(pubkey + pad, pubkey, pubkey_len); ++ os_memset(pubkey, 0, pad); ++ } ++ ++ return 0; ++ #else ++ /* Prefer to use mbedtls to derive our public/private key, as doing so ++ * leverages mbedtls to properly format output and to perform blinding*/ ++ mbedtls_dhm_context ctx; ++ mbedtls_dhm_init(&ctx); ++ int ret = crypto_mbedtls_dh_init_public(&ctx, generator, prime, ++ prime_len, privkey, pubkey); ++ mbedtls_dhm_free(&ctx); ++ return ret; ++ #endif ++} ++ ++/*(crypto_dh_derive_secret() could be implemented using crypto.h APIs ++ * instead of being reimplemented in each crypto_*.c)*/ ++int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len, ++ const u8 *order, size_t order_len, ++ const u8 *privkey, size_t privkey_len, ++ const u8 *pubkey, size_t pubkey_len, ++ u8 *secret, size_t *len) ++{ ++ #if 0 ++ if (pubkey_len > prime_len || ++ (pubkey_len == prime_len && ++ os_memcmp(pubkey, prime, prime_len) >= 0)) ++ return -1; ++ ++ int res = 0; ++ mbedtls_mpi pub; ++ mbedtls_mpi_init(&pub); ++ if (mbedtls_mpi_read_binary(&pub, pubkey, pubkey_len) ++ || mbedtls_mpi_cmp_int(&pub, 1) <= 0) { ++ res = -1; ++ } else if (order) { ++ mbedtls_mpi p, q, tmp; ++ mbedtls_mpi_init(&p); ++ mbedtls_mpi_init(&q); ++ mbedtls_mpi_init(&tmp); ++ ++ /* verify: pubkey^q == 1 mod p */ ++ res = (mbedtls_mpi_read_binary(&p, prime, prime_len) ++ || mbedtls_mpi_read_binary(&q, order, order_len) ++ || mbedtls_mpi_exp_mod(&tmp, &pub, &q, &p, NULL) ++ || mbedtls_mpi_cmp_int(&tmp, 1) != 0); ++ ++ mbedtls_mpi_free(&p); ++ mbedtls_mpi_free(&q); ++ mbedtls_mpi_free(&tmp); ++ } ++ mbedtls_mpi_free(&pub); ++ ++ return (res == 0) ++ ? crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len, ++ prime, prime_len, secret, len) ++ : -1; ++ #else ++ /* Prefer to use mbedtls to derive DH shared secret, as doing so ++ * leverages mbedtls to validate params and to perform blinding. ++ * ++ * Attempt to reconstitute DH context to derive shared secret ++ * (due to limitations of the interface, which ought to pass context). ++ * Force provided G (our private key) into context without validation. ++ * Regenerating GX (our public key) not needed to derive shared secret. ++ */ ++ /*(older compilers might not support VLAs)*/ ++ /*unsigned char buf[2+prime_len+2+1+2+pubkey_len];*/ ++ unsigned char buf[2+MBEDTLS_MPI_MAX_SIZE+2+1+2+MBEDTLS_MPI_MAX_SIZE]; ++ unsigned char *p = buf + 2 + prime_len; ++ if (2+prime_len+2+1+2+pubkey_len > sizeof(buf)) ++ return -1; ++ WPA_PUT_BE16(buf, prime_len); /*(2-byte big-endian size of prime)*/ ++ p[0] = 0; /*(2-byte big-endian size of generator)*/ ++ p[1] = 1; ++ p[2] = generator; ++ WPA_PUT_BE16(p+3, pubkey_len); /*(2-byte big-endian size of pubkey)*/ ++ os_memcpy(p+5, pubkey, pubkey_len); ++ os_memcpy(buf+2, prime, prime_len); ++ ++ mbedtls_dhm_context ctx; ++ mbedtls_dhm_init(&ctx); ++ p = buf; ++ int ret = mbedtls_dhm_read_params(&ctx, &p, p+2+prime_len+5+pubkey_len) ++ || mbedtls_mpi_read_binary(&ctx.MBEDTLS_PRIVATE(X), ++ privkey, privkey_len) ++ || mbedtls_dhm_calc_secret(&ctx, secret, *len, len, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) ? -1 : 0; ++ mbedtls_dhm_free(&ctx); ++ return ret; ++ #endif ++} ++ ++/* dh_group5.c */ ++ ++#include "dh_group5.h" ++ ++/* RFC3526_PRIME_1536[] and RFC3526_GENERATOR_1536[] from crypto_wolfssl.c */ ++ ++static const unsigned char RFC3526_PRIME_1536[] = { ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, ++ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, ++ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, ++ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, ++ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, ++ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, ++ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, ++ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, ++ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, ++ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, ++ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, ++ 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, ++ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, ++ 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, ++ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, ++ 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ++}; ++ ++static const unsigned char RFC3526_GENERATOR_1536[] = { ++ 0x02 ++}; ++ ++void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) ++{ ++ const unsigned char * const prime = RFC3526_PRIME_1536; ++ const size_t prime_len = sizeof(RFC3526_PRIME_1536); ++ const u8 generator = *RFC3526_GENERATOR_1536; ++ struct wpabuf *wpubl = NULL, *wpriv = NULL; ++ ++ mbedtls_dhm_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_dhm_init(ctx); ++ ++ if ( (wpubl = wpabuf_alloc(prime_len)) ++ && (wpriv = wpabuf_alloc(prime_len)) ++ && crypto_mbedtls_dh_init_public(ctx, generator, prime, prime_len, ++ wpabuf_put(wpriv, prime_len), ++ wpabuf_put(wpubl, prime_len))==0) { ++ wpabuf_free(*publ); ++ wpabuf_clear_free(*priv); ++ *publ = wpubl; ++ *priv = wpriv; ++ return ctx; ++ } ++ ++ wpabuf_clear_free(wpriv); ++ wpabuf_free(wpubl); ++ mbedtls_dhm_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++ ++#ifdef CRYPTO_MBEDTLS_DH5_INIT_FIXED ++void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) ++{ ++ const unsigned char * const prime = RFC3526_PRIME_1536; ++ const size_t prime_len = sizeof(RFC3526_PRIME_1536); ++ const u8 generator = *RFC3526_GENERATOR_1536; ++ ++ mbedtls_dhm_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_dhm_init(ctx); ++ ++ if (crypto_mbedtls_dh_set_bin_pg(ctx, generator, prime, prime_len)==0 ++ #if 0 /*(ignore; not required to derive shared secret)*/ ++ && mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(GX), ++ wpabuf_head(publ),wpabuf_len(publ))==0 ++ #endif ++ && mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(X), ++ wpabuf_head(priv),wpabuf_len(priv))==0) { ++ return ctx; ++ } ++ ++ mbedtls_dhm_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++#endif ++ ++struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, ++ const struct wpabuf *own_private) ++{ ++ /*((mbedtls_dhm_context *)ctx must already contain own_private)*/ ++ /* mbedtls 2.x: prime_len = ctx->len; */ ++ /* mbedtls 3.x: prime_len = mbedtls_dhm_get_len(ctx); */ ++ size_t olen = sizeof(RFC3526_PRIME_1536); /*(sizeof(); prime known)*/ ++ struct wpabuf *buf = wpabuf_alloc(olen); ++ if (buf == NULL) ++ return NULL; ++ if (mbedtls_dhm_read_public((mbedtls_dhm_context *)ctx, ++ wpabuf_head(peer_public), ++ wpabuf_len(peer_public)) == 0 ++ && mbedtls_dhm_calc_secret(ctx, wpabuf_mhead(buf), olen, &olen, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) == 0) { ++ wpabuf_put(buf, olen); ++ return buf; ++ } ++ ++ wpabuf_free(buf); ++ return NULL; ++} ++ ++void dh5_free(void *ctx) ++{ ++ mbedtls_dhm_free(ctx); ++ os_free(ctx); ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_DH */ ++ ++ ++#if defined(CRYPTO_MBEDTLS_CRYPTO_ECDH) || defined(CRYPTO_MBEDTLS_CRYPTO_EC) ++ ++#include <mbedtls/ecp.h> ++ ++#define CRYPTO_EC_pbits(e) (((mbedtls_ecp_group *)(e))->pbits) ++#define CRYPTO_EC_plen(e) ((((mbedtls_ecp_group *)(e))->pbits+7)>>3) ++#define CRYPTO_EC_P(e) (&((mbedtls_ecp_group *)(e))->P) ++#define CRYPTO_EC_N(e) (&((mbedtls_ecp_group *)(e))->N) ++#define CRYPTO_EC_A(e) (&((mbedtls_ecp_group *)(e))->A) ++#define CRYPTO_EC_B(e) (&((mbedtls_ecp_group *)(e))->B) ++#define CRYPTO_EC_G(e) (&((mbedtls_ecp_group *)(e))->G) ++ ++static mbedtls_ecp_group_id crypto_mbedtls_ecp_group_id_from_ike_id(int group) ++{ ++ /* https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml */ ++ switch (group) { ++ #ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED ++ case 19: return MBEDTLS_ECP_DP_SECP256R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED ++ case 20: return MBEDTLS_ECP_DP_SECP384R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED ++ case 21: return MBEDTLS_ECP_DP_SECP521R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP192R1_ENABLED ++ case 25: return MBEDTLS_ECP_DP_SECP192R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP224R1_ENABLED ++ case 26: return MBEDTLS_ECP_DP_SECP224R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP256R1_ENABLED ++ case 28: return MBEDTLS_ECP_DP_BP256R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP384R1_ENABLED ++ case 29: return MBEDTLS_ECP_DP_BP384R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP512R1_ENABLED ++ case 30: return MBEDTLS_ECP_DP_BP512R1; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED ++ case 31: return MBEDTLS_ECP_DP_CURVE25519; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED ++ case 32: return MBEDTLS_ECP_DP_CURVE448; ++ #endif ++ default: return MBEDTLS_ECP_DP_NONE; ++ } ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC ++static int crypto_mbedtls_ike_id_from_ecp_group_id(mbedtls_ecp_group_id grp_id) ++{ ++ /* https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml */ ++ /*(for crypto_ec_key_group())*/ ++ switch (grp_id) { ++ #ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP256R1: return 19; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP384R1: return 20; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP521R1: return 21; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP192R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP192R1: return 25; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP224R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP224R1: return 26; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP256R1_ENABLED ++ case MBEDTLS_ECP_DP_BP256R1: return 28; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP384R1_ENABLED ++ case MBEDTLS_ECP_DP_BP384R1: return 29; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP512R1_ENABLED ++ case MBEDTLS_ECP_DP_BP512R1: return 30; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED ++ case MBEDTLS_ECP_DP_CURVE25519: return 31; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED ++ case MBEDTLS_ECP_DP_CURVE448: return 32; ++ #endif ++ default: return -1; ++ } ++} ++#endif ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_ECDH || CRYPTO_MBEDTLS_CRYPTO_EC */ ++ ++ ++#if defined(CRYPTO_MBEDTLS_CRYPTO_ECDH) || defined(CRYPTO_MBEDTLS_CRYPTO_EC_DPP) ++ ++#include <mbedtls/ecp.h> ++#include <mbedtls/pk.h> ++ ++static int crypto_mbedtls_keypair_gen(int group, mbedtls_pk_context *pk) ++{ ++ mbedtls_ecp_group_id grp_id = ++ crypto_mbedtls_ecp_group_id_from_ike_id(group); ++ if (grp_id == MBEDTLS_ECP_DP_NONE) ++ return -1; ++ const mbedtls_pk_info_t *pk_info = ++ mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); ++ if (pk_info == NULL) ++ return -1; ++ return mbedtls_pk_setup(pk, pk_info) ++ || mbedtls_ecp_gen_key(grp_id, mbedtls_pk_ec(*pk), ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) ? -1 : 0; ++} ++ ++#endif ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_ECDH ++ ++#include <mbedtls/ecdh.h> ++#include <mbedtls/ecdsa.h> ++#include <mbedtls/ecp.h> ++#include <mbedtls/pk.h> ++ ++/* wrap mbedtls_ecdh_context for more future-proof direct access to components ++ * (mbedtls_ecdh_context internal implementation may change between releases) ++ * ++ * If mbedtls_pk_context -- specifically underlying mbedtls_ecp_keypair -- ++ * lifetime were guaranteed to be longer than that of mbedtls_ecdh_context, ++ * then mbedtls_pk_context or mbedtls_ecp_keypair could be stored in crypto_ecdh ++ * (or crypto_ec_key could be stored in crypto_ecdh, and crypto_ec_key could ++ * wrap mbedtls_ecp_keypair and components, to avoid MBEDTLS_PRIVATE access) */ ++struct crypto_ecdh { ++ mbedtls_ecdh_context ctx; ++ mbedtls_ecp_group grp; ++ mbedtls_ecp_point Q; ++}; ++ ++struct crypto_ecdh * crypto_ecdh_init(int group) ++{ ++ mbedtls_pk_context pk; ++ mbedtls_pk_init(&pk); ++ struct crypto_ecdh *ecdh = crypto_mbedtls_keypair_gen(group, &pk) == 0 ++ ? crypto_ecdh_init2(group, (struct crypto_ec_key *)&pk) ++ : NULL; ++ mbedtls_pk_free(&pk); ++ return ecdh; ++} ++ ++struct crypto_ecdh * crypto_ecdh_init2(int group, ++ struct crypto_ec_key *own_key) ++{ ++ mbedtls_ecp_group_id grp_id = ++ crypto_mbedtls_ecp_group_id_from_ike_id(group); ++ if (grp_id == MBEDTLS_ECP_DP_NONE) ++ return NULL; ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)own_key); ++ struct crypto_ecdh *ecdh = os_malloc(sizeof(*ecdh)); ++ if (ecdh == NULL) ++ return NULL; ++ mbedtls_ecdh_init(&ecdh->ctx); ++ mbedtls_ecp_group_init(&ecdh->grp); ++ mbedtls_ecp_point_init(&ecdh->Q); ++ if (mbedtls_ecdh_setup(&ecdh->ctx, grp_id) == 0 ++ && mbedtls_ecdh_get_params(&ecdh->ctx,ecp_kp,MBEDTLS_ECDH_OURS) == 0) { ++ /* copy grp and Q for later use ++ * (retrieving this info later is more convoluted ++ * even if mbedtls_ecdh_make_public() is considered)*/ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */ ++ mbedtls_mpi d; ++ mbedtls_mpi_init(&d); ++ if (mbedtls_ecp_export(ecp_kp, &ecdh->grp, &d, &ecdh->Q) == 0) { ++ mbedtls_mpi_free(&d); ++ return ecdh; ++ } ++ mbedtls_mpi_free(&d); ++ #else ++ if (mbedtls_ecp_group_load(&ecdh->grp, grp_id) == 0 ++ && mbedtls_ecp_copy(&ecdh->Q, &ecp_kp->MBEDTLS_PRIVATE(Q)) == 0) ++ return ecdh; ++ #endif ++ } ++ ++ mbedtls_ecp_point_free(&ecdh->Q); ++ mbedtls_ecp_group_free(&ecdh->grp); ++ mbedtls_ecdh_free(&ecdh->ctx); ++ os_free(ecdh); ++ return NULL; ++} ++ ++struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) ++{ ++ mbedtls_ecp_group *grp = &ecdh->grp; ++ size_t len = CRYPTO_EC_plen(grp); ++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED ++ /* len */ ++ #endif ++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED ++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) ++ len = inc_y ? len*2+1 : len+1; ++ #endif ++ struct wpabuf *buf = wpabuf_alloc(len); ++ if (buf == NULL) ++ return NULL; ++ inc_y = inc_y ? MBEDTLS_ECP_PF_UNCOMPRESSED : MBEDTLS_ECP_PF_COMPRESSED; ++ if (mbedtls_ecp_point_write_binary(grp, &ecdh->Q, inc_y, &len, ++ wpabuf_mhead_u8(buf), len) == 0) { ++ wpabuf_put(buf, len); ++ return buf; ++ } ++ ++ wpabuf_free(buf); ++ return NULL; ++} ++ ++#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) ++static int crypto_mbedtls_short_weierstrass_derive_y(mbedtls_ecp_group *grp, ++ mbedtls_mpi *bn, ++ int parity_bit) ++{ ++ /* y^2 = x^3 + ax + b ++ * sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) */ ++ mbedtls_mpi *cy2 = (mbedtls_mpi *) ++ crypto_ec_point_compute_y_sqr((struct crypto_ec *)grp, ++ (const struct crypto_bignum *)bn); /*x*/ ++ if (cy2 == NULL) ++ return -1; ++ ++ /*mbedtls_mpi_free(bn);*/ ++ /*(reuse bn to store result (y))*/ ++ ++ mbedtls_mpi exp; ++ mbedtls_mpi_init(&exp); ++ int ret = mbedtls_mpi_get_bit(&grp->P, 0) != 1 /*(p = 3 mod 4)*/ ++ || mbedtls_mpi_get_bit(&grp->P, 1) != 1 /*(p = 3 mod 4)*/ ++ || mbedtls_mpi_add_int(&exp, &grp->P, 1) ++ || mbedtls_mpi_shift_r(&exp, 2) ++ || mbedtls_mpi_exp_mod(bn, cy2, &exp, &grp->P, NULL) ++ || (mbedtls_mpi_get_bit(bn, 0) != parity_bit ++ && mbedtls_mpi_sub_mpi(bn, &grp->P, bn)); ++ mbedtls_mpi_free(&exp); ++ mbedtls_mpi_free(cy2); ++ os_free(cy2); ++ return ret; ++} ++#endif ++ ++struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, ++ const u8 *key, size_t len) ++{ ++ if (len == 0) /*(invalid peer key)*/ ++ return NULL; ++ ++ mbedtls_ecp_group *grp = &ecdh->grp; ++ ++ #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) ++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { ++ /* add header for mbedtls_ecdh_read_public() */ ++ u8 buf[256]; ++ if (sizeof(buf)-1 < len) ++ return NULL; ++ buf[0] = (u8)(len); ++ os_memcpy(buf+1, key, len); ++ ++ if (inc_y) { ++ if (!(len & 1)) { /*(dpp code/tests does not include tag?!?)*/ ++ if (sizeof(buf)-2 < len) ++ return NULL; ++ buf[0] = (u8)(1+len); ++ buf[1] = 0x04; ++ os_memcpy(buf+2, key, len); ++ } ++ len >>= 1; /*(repurpose len to prime_len)*/ ++ } ++ else if (key[0] == 0x02 || key[0] == 0x03) { /* (inc_y == 0) */ ++ --len; /*(repurpose len to prime_len)*/ ++ ++ /* mbedtls_ecp_point_read_binary() does not currently support ++ * MBEDTLS_ECP_PF_COMPRESSED format (buf[1] = 0x02 or 0x03) ++ * (returns MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) */ ++ ++ /* derive y, amend buf[] with y for UNCOMPRESSED format */ ++ if (sizeof(buf)-2 < len*2 || len == 0) ++ return NULL; ++ buf[0] = (u8)(1+len*2); ++ buf[1] = 0x04; ++ mbedtls_mpi bn; ++ mbedtls_mpi_init(&bn); ++ int ret = mbedtls_mpi_read_binary(&bn, key+1, len) ++ || crypto_mbedtls_short_weierstrass_derive_y(grp, &bn, ++ key[0] & 1) ++ || mbedtls_mpi_write_binary(&bn, buf+2+len, len); ++ mbedtls_mpi_free(&bn); ++ if (ret != 0) ++ return NULL; ++ } ++ ++ if (key[0] == 0) /*(repurpose len to prime_len)*/ ++ len = CRYPTO_EC_plen(grp); ++ ++ if (mbedtls_ecdh_read_public(&ecdh->ctx, buf, buf[0]+1)) ++ return NULL; ++ } ++ #endif ++ #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) ++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { ++ if (mbedtls_ecdh_read_public(&ecdh->ctx, key, len)) ++ return NULL; ++ } ++ #endif ++ ++ struct wpabuf *buf = wpabuf_alloc(len); ++ if (buf == NULL) ++ return NULL; ++ ++ if (mbedtls_ecdh_calc_secret(&ecdh->ctx, &len, ++ wpabuf_mhead(buf), len, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) == 0) { ++ wpabuf_put(buf, len); ++ return buf; ++ } ++ ++ wpabuf_clear_free(buf); ++ return NULL; ++} ++ ++void crypto_ecdh_deinit(struct crypto_ecdh *ecdh) ++{ ++ if (ecdh == NULL) ++ return; ++ mbedtls_ecp_point_free(&ecdh->Q); ++ mbedtls_ecp_group_free(&ecdh->grp); ++ mbedtls_ecdh_free(&ecdh->ctx); ++ os_free(ecdh); ++} ++ ++size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh) ++{ ++ return CRYPTO_EC_plen(&ecdh->grp); ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_ECDH */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC ++ ++#include <mbedtls/ecp.h> ++ ++struct crypto_ec *crypto_ec_init(int group) ++{ ++ mbedtls_ecp_group_id grp_id = ++ crypto_mbedtls_ecp_group_id_from_ike_id(group); ++ if (grp_id == MBEDTLS_ECP_DP_NONE) ++ return NULL; ++ mbedtls_ecp_group *e = os_malloc(sizeof(*e)); ++ if (e == NULL) ++ return NULL; ++ mbedtls_ecp_group_init(e); ++ if (mbedtls_ecp_group_load(e, grp_id) == 0) ++ return (struct crypto_ec *)e; ++ ++ mbedtls_ecp_group_free(e); ++ os_free(e); ++ return NULL; ++} ++ ++void crypto_ec_deinit(struct crypto_ec *e) ++{ ++ mbedtls_ecp_group_free((mbedtls_ecp_group *)e); ++ os_free(e); ++} ++ ++size_t crypto_ec_prime_len(struct crypto_ec *e) ++{ ++ return CRYPTO_EC_plen(e); ++} ++ ++size_t crypto_ec_prime_len_bits(struct crypto_ec *e) ++{ ++ return CRYPTO_EC_pbits(e); ++} ++ ++size_t crypto_ec_order_len(struct crypto_ec *e) ++{ ++ return (mbedtls_mpi_bitlen(CRYPTO_EC_N(e)) + 7) / 8; ++} ++ ++const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e) ++{ ++ return (const struct crypto_bignum *)CRYPTO_EC_P(e); ++} ++ ++const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e) ++{ ++ return (const struct crypto_bignum *)CRYPTO_EC_N(e); ++} ++ ++const struct crypto_bignum *crypto_ec_get_a(struct crypto_ec *e) ++{ ++ static const uint8_t secp256r1_a[] = ++ {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x01, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc}; ++ static const uint8_t secp384r1_a[] = ++ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, ++ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xfc}; ++ static const uint8_t secp521r1_a[] = ++ {0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xfc}; ++ static const uint8_t secp192r1_a[] = ++ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc}; ++ static const uint8_t secp224r1_a[] = ++ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, ++ 0xff,0xff,0xff,0xfe}; ++ ++ const uint8_t *bin = NULL; ++ size_t len = 0; ++ ++ /* (mbedtls groups matching supported sswu_curve_param() IKE groups) */ ++ switch (((mbedtls_ecp_group *)e)->id) { ++ #ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP256R1: ++ bin = secp256r1_a; ++ len = sizeof(secp256r1_a); ++ break; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP384R1: ++ bin = secp384r1_a; ++ len = sizeof(secp384r1_a); ++ break; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP521R1: ++ bin = secp521r1_a; ++ len = sizeof(secp521r1_a); ++ break; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP192R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP192R1: ++ bin = secp192r1_a; ++ len = sizeof(secp192r1_a); ++ break; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_SECP224R1_ENABLED ++ case MBEDTLS_ECP_DP_SECP224R1: ++ bin = secp224r1_a; ++ len = sizeof(secp224r1_a); ++ break; ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP256R1_ENABLED ++ case MBEDTLS_ECP_DP_BP256R1: ++ return (const struct crypto_bignum *)CRYPTO_EC_A(e); ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP384R1_ENABLED ++ case MBEDTLS_ECP_DP_BP384R1: ++ return (const struct crypto_bignum *)CRYPTO_EC_A(e); ++ #endif ++ #ifdef MBEDTLS_ECP_DP_BP512R1_ENABLED ++ case MBEDTLS_ECP_DP_BP512R1: ++ return (const struct crypto_bignum *)CRYPTO_EC_A(e); ++ #endif ++ #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED ++ case MBEDTLS_ECP_DP_CURVE25519: ++ return (const struct crypto_bignum *)CRYPTO_EC_A(e); ++ #endif ++ #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED ++ case MBEDTLS_ECP_DP_CURVE448: ++ return (const struct crypto_bignum *)CRYPTO_EC_A(e); ++ #endif ++ default: ++ return NULL; ++ } ++ ++ /*(note: not thread-safe; returns file-scoped static storage)*/ ++ if (mbedtls_mpi_read_binary(&mpi_sw_A, bin, len) == 0) ++ return (const struct crypto_bignum *)&mpi_sw_A; ++ return NULL; ++} ++ ++const struct crypto_bignum *crypto_ec_get_b(struct crypto_ec *e) ++{ ++ return (const struct crypto_bignum *)CRYPTO_EC_B(e); ++} ++ ++const struct crypto_ec_point * crypto_ec_get_generator(struct crypto_ec *e) ++{ ++ return (const struct crypto_ec_point *)CRYPTO_EC_G(e); ++} ++ ++struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e) ++{ ++ mbedtls_ecp_point *p = os_malloc(sizeof(*p)); ++ if (p != NULL) ++ mbedtls_ecp_point_init(p); ++ return (struct crypto_ec_point *)p; ++} ++ ++void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) ++{ ++ mbedtls_ecp_point_free((mbedtls_ecp_point *)p); ++ os_free(p); ++} ++ ++int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p, ++ struct crypto_bignum *x) ++{ ++ mbedtls_mpi *px = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X); ++ return mbedtls_mpi_copy((mbedtls_mpi *)x, px) ++ ? -1 ++ : 0; ++} ++ ++int crypto_ec_point_to_bin(struct crypto_ec *e, ++ const struct crypto_ec_point *point, u8 *x, u8 *y) ++{ ++ /* crypto.h documents crypto_ec_point_to_bin() output is big-endian */ ++ size_t len = CRYPTO_EC_plen(e); ++ if (x) { ++ mbedtls_mpi *px = &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(X); ++ if (mbedtls_mpi_write_binary(px, x, len)) ++ return -1; ++ } ++ if (y) { ++ #if 0 /*(should not be necessary; py mpi should be in initial state)*/ ++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED ++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) ++ == MBEDTLS_ECP_TYPE_MONTGOMERY) { ++ os_memset(y, 0, len); ++ return 0; ++ } ++ #endif ++ #endif ++ mbedtls_mpi *py = &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(Y); ++ if (mbedtls_mpi_write_binary(py, y, len)) ++ return -1; ++ } ++ return 0; ++} ++ ++struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, ++ const u8 *val) ++{ ++ size_t len = CRYPTO_EC_plen(e); ++ mbedtls_ecp_point *p = os_malloc(sizeof(*p)); ++ u8 buf[1+MBEDTLS_MPI_MAX_SIZE*2]; ++ if (p == NULL) ++ return NULL; ++ mbedtls_ecp_point_init(p); ++ ++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED ++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) ++ == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { ++ #if 0 /* prefer alternative to MBEDTLS_PRIVATE() access */ ++ mbedtls_mpi *px = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X); ++ mbedtls_mpi *py = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y); ++ mbedtls_mpi *pz = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Z); ++ ++ if (mbedtls_mpi_read_binary(px, val, len) == 0 ++ && mbedtls_mpi_read_binary(py, val + len, len) == 0 ++ && mbedtls_mpi_lset(pz, 1) == 0) ++ return (struct crypto_ec_point *)p; ++ #else ++ buf[0] = 0x04; ++ os_memcpy(buf+1, val, len*2); ++ if (mbedtls_ecp_point_read_binary((mbedtls_ecp_group *)e, p, ++ buf, 1+len*2) == 0) ++ return (struct crypto_ec_point *)p; ++ #endif ++ } ++ #endif ++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED ++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) ++ == MBEDTLS_ECP_TYPE_MONTGOMERY) { ++ /* crypto.h interface documents crypto_ec_point_from_bin() ++ * val is length: prime_len * 2 and is big-endian ++ * (Short Weierstrass is assumed by hostap) ++ * Reverse to little-endian format for Montgomery */ ++ for (unsigned int i = 0; i < len; ++i) ++ buf[i] = val[len-1-i]; ++ if (mbedtls_ecp_point_read_binary((mbedtls_ecp_group *)e, p, ++ buf, len) == 0) ++ return (struct crypto_ec_point *)p; ++ } ++ #endif ++ ++ mbedtls_ecp_point_free(p); ++ os_free(p); ++ return NULL; ++} ++ ++int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, ++ const struct crypto_ec_point *b, ++ struct crypto_ec_point *c) ++{ ++ /* mbedtls does not provide an mbedtls_ecp_point add function */ ++ mbedtls_mpi one; ++ mbedtls_mpi_init(&one); ++ int ret = mbedtls_mpi_lset(&one, 1) ++ || mbedtls_ecp_muladd( ++ (mbedtls_ecp_group *)e, (mbedtls_ecp_point *)c, ++ &one, (const mbedtls_ecp_point *)a, ++ &one, (const mbedtls_ecp_point *)b) ? -1 : 0; ++ mbedtls_mpi_free(&one); ++ return ret; ++} ++ ++int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, ++ const struct crypto_bignum *b, ++ struct crypto_ec_point *res) ++{ ++ return mbedtls_ecp_mul( ++ (mbedtls_ecp_group *)e, (mbedtls_ecp_point *)res, ++ (const mbedtls_mpi *)b, (const mbedtls_ecp_point *)p, ++ mbedtls_ctr_drbg_random, crypto_mbedtls_ctr_drbg()) ? -1 : 0; ++} ++ ++int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) ++{ ++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) ++ == MBEDTLS_ECP_TYPE_MONTGOMERY) { ++ /* e.g. MBEDTLS_ECP_DP_CURVE25519 and MBEDTLS_ECP_DP_CURVE448 */ ++ wpa_printf(MSG_ERROR, ++ "%s not implemented for Montgomery curves",__func__); ++ return -1; ++ } ++ ++ /* mbedtls does not provide an mbedtls_ecp_point invert function */ ++ /* below works for Short Weierstrass; incorrect for Montgomery curves */ ++ mbedtls_mpi *py = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y); ++ return mbedtls_ecp_is_zero((mbedtls_ecp_point *)p) /*point at infinity*/ ++ || mbedtls_mpi_cmp_int(py, 0) == 0 /*point is its own inverse*/ ++ || mbedtls_mpi_sub_abs(py, CRYPTO_EC_P(e), py) == 0 ? 0 : -1; ++} ++ ++#ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED ++static int ++crypto_ec_point_y_sqr_weierstrass(mbedtls_ecp_group *e, const mbedtls_mpi *x, ++ mbedtls_mpi *y2) ++{ ++ /* MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS y^2 = x^3 + a x + b */ ++ ++ /* Short Weierstrass elliptic curve group w/o A set treated as A = -3 */ ++ /* Attempt to match mbedtls/library/ecp.c:ecp_check_pubkey_sw() behavior ++ * and elsewhere in mbedtls/library/ecp.c where if A is not set, it is ++ * treated as if A = -3. */ ++ ++ #if 0 ++ /* y^2 = x^3 + ax + b */ ++ mbedtls_mpi *A = &e->A; ++ mbedtls_mpi t, A_neg3; ++ if (&e->A.p == NULL) { ++ mbedtls_mpi_init(&A_neg3); ++ if (mbedtls_mpi_lset(&A_neg3, -3) != 0) { ++ mbedtls_mpi_free(&A_neg3); ++ return -1; ++ } ++ A = &A_neg3; ++ } ++ mbedtls_mpi_init(&t); ++ int ret = /* x^3 */ ++ mbedtls_mpi_lset(&t, 3) ++ || mbedtls_mpi_exp_mod(y2, x, &t, &e->P, NULL) ++ /* ax */ ++ || mbedtls_mpi_mul_mpi(y2, y2, A) ++ || mbedtls_mpi_mod_mpi(&t, &t, &e->P) ++ /* ax + b */ ++ || mbedtls_mpi_add_mpi(&t, &t, &e->B) ++ || mbedtls_mpi_mod_mpi(&t, &t, &e->P) ++ /* x^3 + ax + b */ ++ || mbedtls_mpi_add_mpi(&t, &t, y2) /* ax + b + x^3 */ ++ || mbedtls_mpi_mod_mpi(y2, &t, &e->P); ++ mbedtls_mpi_free(&t); ++ if (A == &A_neg3) ++ mbedtls_mpi_free(&A_neg3); ++ return ret; /* 0: success, non-zero: failure */ ++ #else ++ /* y^2 = x^3 + ax + b = (x^2 + a)x + b */ ++ return /* x^2 */ ++ mbedtls_mpi_mul_mpi(y2, x, x) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P) ++ /* x^2 + a */ ++ || (e->A.MBEDTLS_PRIVATE(p) ++ ? mbedtls_mpi_add_mpi(y2, y2, &e->A) ++ : mbedtls_mpi_sub_int(y2, y2, 3)) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P) ++ /* (x^2 + a)x */ ++ || mbedtls_mpi_mul_mpi(y2, y2, x) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P) ++ /* (x^2 + a)x + b */ ++ || mbedtls_mpi_add_mpi(y2, y2, &e->B) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P); ++ #endif ++} ++#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ ++ ++#if 0 /* not used by hostap */ ++#ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED ++static int ++crypto_ec_point_y_sqr_montgomery(mbedtls_ecp_group *e, const mbedtls_mpi *x, ++ mbedtls_mpi *y2) ++{ ++ /* XXX: !!! must be reviewed and audited for correctness !!! */ ++ ++ /* MBEDTLS_ECP_TYPE_MONTGOMERY y^2 = x^3 + a x^2 + x */ ++ ++ /* y^2 = x^3 + a x^2 + x = (x + a)x^2 + x */ ++ mbedtls_mpi x2; ++ mbedtls_mpi_init(&x2); ++ int ret = /* x^2 */ ++ mbedtls_mpi_mul_mpi(&x2, x, x) ++ || mbedtls_mpi_mod_mpi(&x2, &x2, &e->P) ++ /* x + a */ ++ || mbedtls_mpi_add_mpi(y2, x, &e->A) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P) ++ /* (x + a)x^2 */ ++ || mbedtls_mpi_mul_mpi(y2, y2, &x2) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P) ++ /* (x + a)x^2 + x */ ++ || mbedtls_mpi_add_mpi(y2, y2, x) ++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P); ++ mbedtls_mpi_free(&x2); ++ return ret; /* 0: success, non-zero: failure */ ++} ++#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ ++#endif ++ ++struct crypto_bignum * ++crypto_ec_point_compute_y_sqr(struct crypto_ec *e, ++ const struct crypto_bignum *x) ++{ ++ mbedtls_mpi *y2 = os_malloc(sizeof(*y2)); ++ if (y2 == NULL) ++ return NULL; ++ mbedtls_mpi_init(y2); ++ ++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED ++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) ++ == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ++ && crypto_ec_point_y_sqr_weierstrass((mbedtls_ecp_group *)e, ++ (const mbedtls_mpi *)x, ++ y2) == 0) ++ return (struct crypto_bignum *)y2; ++ #endif ++ #if 0 /* not used by hostap */ ++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED ++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) ++ == MBEDTLS_ECP_TYPE_MONTGOMERY ++ && crypto_ec_point_y_sqr_montgomery((mbedtls_ecp_group *)e, ++ (const mbedtls_mpi *)x, ++ y2) == 0) ++ return (struct crypto_bignum *)y2; ++ #endif ++ #endif ++ ++ mbedtls_mpi_free(y2); ++ os_free(y2); ++ return NULL; ++} ++ ++int crypto_ec_point_is_at_infinity(struct crypto_ec *e, ++ const struct crypto_ec_point *p) ++{ ++ return mbedtls_ecp_is_zero((mbedtls_ecp_point *)p); ++} ++ ++int crypto_ec_point_is_on_curve(struct crypto_ec *e, ++ const struct crypto_ec_point *p) ++{ ++ #if 1 ++ return mbedtls_ecp_check_pubkey((const mbedtls_ecp_group *)e, ++ (const mbedtls_ecp_point *)p) == 0; ++ #else ++ /* compute y^2 mod P and compare to y^2 mod P */ ++ /*(ref: src/eap_common/eap_pwd_common.c:compute_password_element())*/ ++ const mbedtls_mpi *px = &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X); ++ mbedtls_mpi *cy2 = (mbedtls_mpi *) ++ crypto_ec_point_compute_y_sqr(e, (const struct crypto_bignum *)px); ++ if (cy2 == NULL) ++ return 0; ++ ++ mbedtls_mpi y2; ++ mbedtls_mpi_init(&y2); ++ const mbedtls_mpi *py = &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y); ++ int is_on_curve = mbedtls_mpi_mul_mpi(&y2, py, py) /* y^2 mod P */ ++ || mbedtls_mpi_mod_mpi(&y2, &y2, CRYPTO_EC_P(e)) ++ || mbedtls_mpi_cmp_mpi(&y2, cy2) != 0 ? 0 : 1; ++ ++ mbedtls_mpi_free(&y2); ++ mbedtls_mpi_free(cy2); ++ os_free(cy2); ++ return is_on_curve; ++ #endif ++} ++ ++int crypto_ec_point_cmp(const struct crypto_ec *e, ++ const struct crypto_ec_point *a, ++ const struct crypto_ec_point *b) ++{ ++ return mbedtls_ecp_point_cmp((const mbedtls_ecp_point *)a, ++ (const mbedtls_ecp_point *)b); ++} ++ ++#if !defined(CONFIG_NO_STDOUT_DEBUG) ++void crypto_ec_point_debug_print(const struct crypto_ec *e, ++ const struct crypto_ec_point *p, ++ const char *title) ++{ ++ u8 x[MBEDTLS_MPI_MAX_SIZE]; ++ u8 y[MBEDTLS_MPI_MAX_SIZE]; ++ size_t len = CRYPTO_EC_plen(e); ++ /* crypto_ec_point_to_bin ought to take (const struct crypto_ec *e) */ ++ struct crypto_ec *ee; ++ *(const struct crypto_ec **)&ee = e; /*(cast away const)*/ ++ if (crypto_ec_point_to_bin(ee, p, x, y) == 0) { ++ if (title) ++ wpa_printf(MSG_DEBUG, "%s", title); ++ wpa_hexdump(MSG_DEBUG, "x:", x, len); ++ wpa_hexdump(MSG_DEBUG, "y:", y, len); ++ } ++} ++#endif ++ ++ ++struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len) ++{ ++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_pk_init(ctx); ++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++ if (mbedtls_pk_parse_key(ctx, der, der_len, NULL, 0) == 0) ++ #else ++ if (mbedtls_pk_parse_key(ctx, der, der_len, NULL, 0, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) == 0) ++ #endif ++ return (struct crypto_ec_key *)ctx; ++ ++ mbedtls_pk_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_HPKE ++#ifdef CONFIG_MODULE_TESTS ++/*(for crypto_module_tests.c)*/ ++struct crypto_ec_key * crypto_ec_key_set_priv(int group, ++ const u8 *raw, size_t raw_len) ++{ ++ mbedtls_ecp_group_id grp_id = ++ crypto_mbedtls_ecp_group_id_from_ike_id(group); ++ if (grp_id == MBEDTLS_ECP_DP_NONE) ++ return NULL; ++ const mbedtls_pk_info_t *pk_info = ++ mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); ++ if (pk_info == NULL) ++ return NULL; ++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_pk_init(ctx); ++ if (mbedtls_pk_setup(ctx, pk_info) == 0 ++ && mbedtls_ecp_read_key(grp_id,mbedtls_pk_ec(*ctx),raw,raw_len) == 0) { ++ return (struct crypto_ec_key *)ctx; ++ } ++ ++ mbedtls_pk_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++#endif ++#endif ++ ++#include <mbedtls/error.h> ++#include <mbedtls/oid.h> ++static int crypto_mbedtls_pk_parse_subpubkey_compressed(mbedtls_pk_context *ctx, const u8 *der, size_t der_len) ++{ ++ /* The following is modified from: ++ * mbedtls/library/pkparse.c:mbedtls_pk_parse_subpubkey() ++ * mbedtls/library/pkparse.c:pk_get_pk_alg() ++ * mbedtls/library/pkparse.c:pk_use_ecparams() ++ */ ++ mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; ++ const mbedtls_pk_info_t *pk_info; ++ int ret; ++ size_t len; ++ const unsigned char *end = der+der_len; ++ unsigned char *p; ++ *(const unsigned char **)&p = der; ++ ++ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) ++ { ++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) ); ++ } ++ ++ end = p + len; ++ ++ /* ++ if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, &alg_params ) ) != 0 ) ++ return( ret ); ++ */ ++ mbedtls_asn1_buf alg_oid, params; ++ memset( ¶ms, 0, sizeof(mbedtls_asn1_buf) ); ++ if( ( ret = mbedtls_asn1_get_alg( &p, end, &alg_oid, ¶ms ) ) != 0 ) ++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_ALG, ret ) ); ++ if( mbedtls_oid_get_pk_alg( &alg_oid, &pk_alg ) != 0 ) ++ return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); ++ ++ if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end, &len ) ) != 0 ) ++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) ); ++ ++ if( p + len != end ) ++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ++ MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); ++ ++ if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) ++ return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); ++ ++ if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) ++ return( ret ); ++ ++ /* assume mbedtls_pk_parse_subpubkey(&der, der+der_len, ctx) ++ * has already run with ctx initialized up to pk_get_ecpubkey(), ++ * and pk_get_ecpubkey() has returned MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ++ * ++ * mbedtls mbedtls_ecp_point_read_binary() ++ * does not handle point in COMPRESSED format ++ * ++ * (validate assumption that algorithm is EC) */ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*ctx); ++ if (ecp_kp == NULL) ++ return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); ++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q); ++ mbedtls_ecp_group_id grp_id; ++ ++ ++ /* mbedtls/library/pkparse.c:pk_use_ecparams() */ ++ ++ if( params.tag == MBEDTLS_ASN1_OID ) ++ { ++ if( mbedtls_oid_get_ec_grp( ¶ms, &grp_id ) != 0 ) ++ return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); ++ } ++ else ++ { ++#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) ++ /*(large code block not copied from mbedtls; unsupported)*/ ++ #if 0 ++ if( ( ret = pk_group_id_from_specified( ¶ms, &grp_id ) ) != 0 ) ++ return( ret ); ++ #endif ++#endif ++ return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); ++ } ++ ++ /* ++ * grp may already be initialized; if so, make sure IDs match ++ */ ++ if( ecp_kp_grp->id != MBEDTLS_ECP_DP_NONE && ecp_kp_grp->id != grp_id ) ++ return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); ++ ++ if( ( ret = mbedtls_ecp_group_load( ecp_kp_grp, grp_id ) ) != 0 ) ++ return( ret ); ++ ++ ++ /* (validate assumption that EC point is in COMPRESSED format) */ ++ len = CRYPTO_EC_plen(ecp_kp_grp); ++ if( mbedtls_ecp_get_type(ecp_kp_grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ++ || (end - p) != 1+len ++ || (*p != 0x02 && *p != 0x03) ) ++ return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); ++ ++ /* Instead of calling mbedtls/library/pkparse.c:pk_get_ecpubkey() to call ++ * mbedtls_ecp_point_read_binary(), manually parse point into ecp_kp_Q */ ++ mbedtls_mpi *X = &ecp_kp_Q->MBEDTLS_PRIVATE(X); ++ mbedtls_mpi *Y = &ecp_kp_Q->MBEDTLS_PRIVATE(Y); ++ mbedtls_mpi *Z = &ecp_kp_Q->MBEDTLS_PRIVATE(Z); ++ ret = mbedtls_mpi_lset(Z, 1); ++ if (ret != 0) ++ return( ret ); ++ ret = mbedtls_mpi_read_binary(X, p+1, len); ++ if (ret != 0) ++ return( ret ); ++ /* derive Y ++ * (similar derivation of Y in crypto_mbedtls.c:crypto_ecdh_set_peerkey())*/ ++ ret = mbedtls_mpi_copy(Y, X) /*(Y is used as input and output obj below)*/ ++ || crypto_mbedtls_short_weierstrass_derive_y(ecp_kp_grp, Y, (*p & 1)); ++ if (ret != 0) ++ return( ret ); ++ ++ return mbedtls_ecp_check_pubkey( ecp_kp_grp, ecp_kp_Q ); ++} ++ ++struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len) ++{ ++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_pk_init(ctx); ++ /*int rc = mbedtls_pk_parse_subpubkey(&der, der+der_len, ctx);*/ ++ int rc = mbedtls_pk_parse_public_key(ctx, der, der_len); ++ if (rc == 0) ++ return (struct crypto_ec_key *)ctx; ++ else if (rc == MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) { ++ /* mbedtls mbedtls_ecp_point_read_binary() ++ * does not handle point in COMPRESSED format; parse internally */ ++ rc = crypto_mbedtls_pk_parse_subpubkey_compressed(ctx,der,der_len); ++ if (rc == 0) ++ return (struct crypto_ec_key *)ctx; ++ } ++ ++ mbedtls_pk_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP ++ ++static struct crypto_ec_key * ++crypto_ec_key_set_pub_point_for_group(mbedtls_ecp_group_id grp_id, ++ const mbedtls_ecp_point *pub, ++ const u8 *buf, size_t len) ++{ ++ const mbedtls_pk_info_t *pk_info = ++ mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); ++ if (pk_info == NULL) ++ return NULL; ++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_pk_init(ctx); ++ if (mbedtls_pk_setup(ctx, pk_info) == 0) { ++ /* (Is private key generation necessary for callers?) ++ * alt: gen key then overwrite Q ++ * mbedtls_ecp_gen_key(grp_id, ecp_kp, ++ * mbedtls_ctr_drbg_random, ++ * crypto_mbedtls_ctr_drbg()) == 0 ++ */ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*ctx); ++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q); ++ mbedtls_mpi *ecp_kp_d = &ecp_kp->MBEDTLS_PRIVATE(d); ++ if (mbedtls_ecp_group_load(ecp_kp_grp, grp_id) == 0 ++ && (pub ++ ? mbedtls_ecp_copy(ecp_kp_Q, pub) == 0 ++ : mbedtls_ecp_point_read_binary(ecp_kp_grp, ecp_kp_Q, ++ buf, len) == 0) ++ && mbedtls_ecp_gen_privkey(ecp_kp_grp, ecp_kp_d, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) == 0){ ++ return (struct crypto_ec_key *)ctx; ++ } ++ } ++ ++ mbedtls_pk_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++ ++struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *x, ++ const u8 *y, size_t len) ++{ ++ mbedtls_ecp_group_id grp_id = ++ crypto_mbedtls_ecp_group_id_from_ike_id(group); ++ if (grp_id == MBEDTLS_ECP_DP_NONE) ++ return NULL; ++ if (len > MBEDTLS_MPI_MAX_SIZE) ++ return NULL; ++ u8 buf[1+MBEDTLS_MPI_MAX_SIZE*2]; ++ buf[0] = 0x04; /* assume x,y for Short Weierstrass */ ++ os_memcpy(buf+1, x, len); ++ os_memcpy(buf+1+len, y, len); ++ ++ return crypto_ec_key_set_pub_point_for_group(grp_id,NULL,buf,1+len*2); ++} ++ ++struct crypto_ec_key * ++crypto_ec_key_set_pub_point(struct crypto_ec *e, ++ const struct crypto_ec_point *pub) ++{ ++ mbedtls_ecp_group_id grp_id = ((mbedtls_ecp_group *)e)->id; ++ mbedtls_ecp_point *p = (mbedtls_ecp_point *)pub; ++ return crypto_ec_key_set_pub_point_for_group(grp_id, p, NULL, 0); ++} ++ ++ ++struct crypto_ec_key * crypto_ec_key_gen(int group) ++{ ++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) ++ return NULL; ++ mbedtls_pk_init(ctx); ++ if (crypto_mbedtls_keypair_gen(group, ctx) == 0) ++ return (struct crypto_ec_key *)ctx; ++ mbedtls_pk_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */ ++ ++void crypto_ec_key_deinit(struct crypto_ec_key *key) ++{ ++ mbedtls_pk_free((mbedtls_pk_context *)key); ++ os_free(key); ++} ++ ++struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key) ++{ ++ /* (similar to crypto_ec_key_get_pubkey_point(), ++ * but compressed point format and ASN.1 DER wrapping)*/ ++#ifndef MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES /*(mbedtls/library/pkwrite.h)*/ ++#define MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES ( 30 + 2 * MBEDTLS_ECP_MAX_BYTES ) ++#endif ++ unsigned char buf[MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES]; ++ int len = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)key, ++ buf, sizeof(buf)); ++ if (len < 0) ++ return NULL; ++ /* Note: data is written at the end of the buffer! Use the ++ * return value to determine where you should start ++ * using the buffer */ ++ unsigned char *p = buf+sizeof(buf)-len; ++ ++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return NULL; ++ mbedtls_ecp_group *grp = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ /* Note: sae_pk.c expects pubkey point in compressed format, ++ * but mbedtls_pk_write_pubkey_der() writes uncompressed format. ++ * Manually translate format and update lengths in DER format */ ++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { ++ unsigned char *end = buf+sizeof(buf); ++ size_t n; ++ /* SubjectPublicKeyInfo SEQUENCE */ ++ mbedtls_asn1_get_tag(&p, end, &n, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ /* algorithm AlgorithmIdentifier */ ++ unsigned char *a = p; ++ size_t alen; ++ mbedtls_asn1_get_tag(&p, end, &alen, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ p += alen; ++ alen = (size_t)(p - a); ++ /* subjectPublicKey BIT STRING */ ++ mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_BIT_STRING); ++ /* rewrite into compressed point format and rebuild ASN.1 */ ++ p[1] = (buf[sizeof(buf)-1] & 1) ? 0x03 : 0x02; ++ n = 1 + 1 + (n-2)/2; ++ len = mbedtls_asn1_write_len(&p, buf, n) + (int)n; ++ len += mbedtls_asn1_write_tag(&p, buf, MBEDTLS_ASN1_BIT_STRING); ++ os_memmove(p-alen, a, alen); ++ len += alen; ++ p -= alen; ++ len += mbedtls_asn1_write_len(&p, buf, (size_t)len); ++ len += mbedtls_asn1_write_tag(&p, buf, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ } ++ #endif ++ return wpabuf_alloc_copy(p, (size_t)len); ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP ++ ++struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key, ++ bool include_pub) ++{ ++#ifndef MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES /*(mbedtls/library/pkwrite.h)*/ ++#define MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES ( 29 + 3 * MBEDTLS_ECP_MAX_BYTES ) ++#endif ++ unsigned char priv[MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES]; ++ int privlen = mbedtls_pk_write_key_der((mbedtls_pk_context *)key, ++ priv, sizeof(priv)); ++ if (privlen < 0) ++ return NULL; ++ ++ struct wpabuf *wbuf; ++ ++ /* Note: data is written at the end of the buffer! Use the ++ * return value to determine where you should start ++ * using the buffer */ ++ /* mbedtls_pk_write_key_der() includes publicKey in DER */ ++ if (include_pub) ++ wbuf = wpabuf_alloc_copy(priv+sizeof(priv)-privlen, privlen); ++ else { ++ /* calculate publicKey offset and skip from end of buffer */ ++ unsigned char *p = priv+sizeof(priv)-privlen; ++ unsigned char *end = priv+sizeof(priv); ++ size_t len; ++ /* ECPrivateKey SEQUENCE */ ++ mbedtls_asn1_get_tag(&p, end, &len, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ /* version INTEGER */ ++ unsigned char *v = p; ++ mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); ++ p += len; ++ /* privateKey OCTET STRING */ ++ mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); ++ p += len; ++ /* parameters ECParameters */ ++ mbedtls_asn1_get_tag(&p, end, &len, ++ MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED); ++ p += len; ++ ++ /* write new SEQUENCE header (we know that it fits in priv[]) */ ++ len = (size_t)(p - v); ++ p = v; ++ len += mbedtls_asn1_write_len(&p, priv, len); ++ len += mbedtls_asn1_write_tag(&p, priv, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ wbuf = wpabuf_alloc_copy(p, len); ++ } ++ ++ forced_memzero(priv, sizeof(priv)); ++ return wbuf; ++} ++ ++struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key, ++ int prefix) ++{ ++ /*(similarities to crypto_ecdh_get_pubkey(), but different struct)*/ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return NULL; ++ mbedtls_ecp_group *grp = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ size_t len = CRYPTO_EC_plen(grp); ++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED ++ /* len */ ++ #endif ++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED ++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) ++ len = len*2+1; ++ #endif ++ struct wpabuf *buf = wpabuf_alloc(len); ++ if (buf == NULL) ++ return NULL; ++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q); ++ if (mbedtls_ecp_point_write_binary(grp, ecp_kp_Q, ++ MBEDTLS_ECP_PF_UNCOMPRESSED, &len, ++ wpabuf_mhead_u8(buf), len) == 0) { ++ if (!prefix) /* Remove 0x04 prefix if requested */ ++ os_memmove(wpabuf_mhead(buf),wpabuf_mhead(buf)+1,--len); ++ wpabuf_put(buf, len); ++ return buf; ++ } ++ ++ wpabuf_free(buf); ++ return NULL; ++} ++ ++struct crypto_ec_point * ++crypto_ec_key_get_public_key(struct crypto_ec_key *key) ++{ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return NULL; ++ mbedtls_ecp_point *p = os_malloc(sizeof(*p)); ++ if (p != NULL) { ++ /*(mbedtls_ecp_export() uses &ecp_kp->MBEDTLS_PRIVATE(grp))*/ ++ mbedtls_ecp_point_init(p); ++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q); ++ if (mbedtls_ecp_copy(p, ecp_kp_Q)) { ++ mbedtls_ecp_point_free(p); ++ os_free(p); ++ p = NULL; ++ } ++ } ++ return (struct crypto_ec_point *)p; ++} ++ ++struct crypto_bignum * ++crypto_ec_key_get_private_key(struct crypto_ec_key *key) ++{ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return NULL; ++ mbedtls_mpi *bn = os_malloc(sizeof(*bn)); ++ if (bn) { ++ /*(mbedtls_ecp_export() uses &ecp_kp->MBEDTLS_PRIVATE(grp))*/ ++ mbedtls_mpi_init(bn); ++ mbedtls_mpi *ecp_kp_d = &ecp_kp->MBEDTLS_PRIVATE(d); ++ if (mbedtls_mpi_copy(bn, ecp_kp_d)) { ++ mbedtls_mpi_free(bn); ++ os_free(bn); ++ bn = NULL; ++ } ++ } ++ return (struct crypto_bignum *)bn; ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */ ++ ++static mbedtls_md_type_t crypto_ec_key_sign_md(size_t len) ++{ ++ /* get mbedtls_md_type_t from length of hash data to be signed */ ++ switch (len) { ++ case 64: return MBEDTLS_MD_SHA512; ++ case 48: return MBEDTLS_MD_SHA384; ++ case 32: return MBEDTLS_MD_SHA256; ++ case 20: return MBEDTLS_MD_SHA1; ++ case 16: return MBEDTLS_MD_MD5; ++ default: return MBEDTLS_MD_NONE; ++ } ++} ++ ++struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, ++ size_t len) ++{ ++ #ifndef MBEDTLS_PK_SIGNATURE_MAX_SIZE /*(defined since mbedtls 2.20.0)*/ ++ #if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE ++ #define MBEDTLS_PK_SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN ++ #else ++ #define MBEDTLS_PK_SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE ++ #endif ++ #endif ++ size_t sig_len = MBEDTLS_PK_SIGNATURE_MAX_SIZE; ++ struct wpabuf *buf = wpabuf_alloc(sig_len); ++ if (buf == NULL) ++ return NULL; ++ if (mbedtls_pk_sign((mbedtls_pk_context *)key, ++ crypto_ec_key_sign_md(len), data, len, ++ wpabuf_mhead_u8(buf), ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ sig_len, ++ #endif ++ &sig_len, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) == 0) { ++ wpabuf_put(buf, sig_len); ++ return buf; ++ } ++ ++ wpabuf_free(buf); ++ return NULL; ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP ++struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, ++ const u8 *data, size_t len) ++{ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return NULL; ++ ++ size_t sig_len = MBEDTLS_ECDSA_MAX_LEN; ++ u8 buf[MBEDTLS_ECDSA_MAX_LEN]; ++ if (mbedtls_ecdsa_write_signature(ecp_kp, crypto_ec_key_sign_md(len), ++ data, len, buf, ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ sig_len, ++ #endif ++ &sig_len, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg())) { ++ return NULL; ++ } ++ ++ /*(mbedtls_ecdsa_write_signature() writes signature in ASN.1)*/ ++ /* parse ASN.1 to get r and s and lengths */ ++ u8 *p = buf, *r, *s; ++ u8 *end = p + sig_len; ++ size_t rlen, slen; ++ mbedtls_asn1_get_tag(&p, end, &rlen, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ mbedtls_asn1_get_tag(&p, end, &rlen, MBEDTLS_ASN1_INTEGER); ++ r = p; ++ p += rlen; ++ mbedtls_asn1_get_tag(&p, end, &slen, MBEDTLS_ASN1_INTEGER); ++ s = p; ++ ++ /* write raw r and s into out ++ * (including removal of leading 0 if added for ASN.1 integer) ++ * note: DPP caller expects raw r, s each padded to prime len */ ++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ size_t plen = CRYPTO_EC_plen(ecp_kp_grp); ++ if (rlen > plen) { ++ r += (rlen - plen); ++ rlen = plen; ++ } ++ if (slen > plen) { ++ s += (slen - plen); ++ slen = plen; ++ } ++ struct wpabuf *out = wpabuf_alloc(plen*2); ++ if (out) { ++ wpabuf_put(out, plen*2); ++ p = wpabuf_mhead_u8(out); ++ os_memset(p, 0, plen*2); ++ os_memcpy(p+plen*1-rlen, r, rlen); ++ os_memcpy(p+plen*2-slen, s, slen); ++ } ++ return out; ++} ++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */ ++ ++int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data, ++ size_t len, const u8 *sig, size_t sig_len) ++{ ++ switch (mbedtls_pk_verify((mbedtls_pk_context *)key, ++ crypto_ec_key_sign_md(len), data, len, ++ sig, sig_len)) { ++ case 0: ++ /*case MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH:*//* XXX: allow? */ ++ return 1; ++ case MBEDTLS_ERR_ECP_VERIFY_FAILED: ++ return 0; ++ default: ++ return -1; ++ } ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP ++int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key, ++ const u8 *data, size_t len, ++ const u8 *r, size_t r_len, ++ const u8 *s, size_t s_len) ++{ ++ /* reimplement mbedtls_ecdsa_read_signature() without encoding r and s ++ * into ASN.1 just for mbedtls_ecdsa_read_signature() to decode ASN.1 */ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return -1; ++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q); ++ ++ mbedtls_mpi mpi_r; ++ mbedtls_mpi mpi_s; ++ mbedtls_mpi_init(&mpi_r); ++ mbedtls_mpi_init(&mpi_s); ++ int ret = mbedtls_mpi_read_binary(&mpi_r, r, r_len) ++ || mbedtls_mpi_read_binary(&mpi_s, s, s_len) ? -1 : 0; ++ if (ret == 0) { ++ ret = mbedtls_ecdsa_verify(ecp_kp_grp, data, len, ++ ecp_kp_Q, &mpi_r, &mpi_s); ++ ret = ret ? ret == MBEDTLS_ERR_ECP_BAD_INPUT_DATA ? 0 : -1 : 1; ++ } ++ mbedtls_mpi_free(&mpi_r); ++ mbedtls_mpi_free(&mpi_s); ++ return ret; ++} ++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */ ++ ++int crypto_ec_key_group(struct crypto_ec_key *key) ++{ ++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key); ++ if (ecp_kp == NULL) ++ return -1; ++ mbedtls_ecp_group *ecp_group = &ecp_kp->MBEDTLS_PRIVATE(grp); ++ return crypto_mbedtls_ike_id_from_ecp_group_id(ecp_group->id); ++} ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP ++ ++int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2) ++{ ++#if 0 /*(DPP is passing two public keys; unable to use pk_check_pair())*/ ++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++ return mbedtls_pk_check_pair((const mbedtls_pk_context *)key1, ++ (const mbedtls_pk_context *)key2) ? -1 : 0; ++ #else ++ return mbedtls_pk_check_pair((const mbedtls_pk_context *)key1, ++ (const mbedtls_pk_context *)key2, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()) ? -1 : 0; ++ #endif ++#else ++ mbedtls_ecp_keypair *ecp_kp1=mbedtls_pk_ec(*(mbedtls_pk_context *)key1); ++ mbedtls_ecp_keypair *ecp_kp2=mbedtls_pk_ec(*(mbedtls_pk_context *)key2); ++ if (ecp_kp1 == NULL || ecp_kp2 == NULL) ++ return -1; ++ mbedtls_ecp_group *ecp_kp1_grp = &ecp_kp1->MBEDTLS_PRIVATE(grp); ++ mbedtls_ecp_group *ecp_kp2_grp = &ecp_kp2->MBEDTLS_PRIVATE(grp); ++ mbedtls_ecp_point *ecp_kp1_Q = &ecp_kp1->MBEDTLS_PRIVATE(Q); ++ mbedtls_ecp_point *ecp_kp2_Q = &ecp_kp2->MBEDTLS_PRIVATE(Q); ++ return ecp_kp1_grp->id != ecp_kp2_grp->id ++ || mbedtls_ecp_point_cmp(ecp_kp1_Q, ecp_kp2_Q) ? -1 : 0; ++#endif ++} ++ ++void crypto_ec_key_debug_print(const struct crypto_ec_key *key, ++ const char *title) ++{ ++ /* TBD: what info is desirable here and in what human readable format?*/ ++ /*(crypto_openssl.c prints a human-readably public key and attributes)*/ ++ #if 0 ++ struct mbedtls_pk_debug_item debug_item; ++ if (mbedtls_pk_debug((const mbedtls_pk_context *)key, &debug_item)) ++ return; ++ /* ... */ ++ #endif ++ wpa_printf(MSG_DEBUG, "%s: %s not implemented", title, __func__); ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */ ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_CSR ++ ++#include <mbedtls/x509_csr.h> ++#include <mbedtls/oid.h> ++ ++struct crypto_csr * crypto_csr_init(void) ++{ ++ mbedtls_x509write_csr *csr = os_malloc(sizeof(*csr)); ++ if (csr != NULL) ++ mbedtls_x509write_csr_init(csr); ++ return (struct crypto_csr *)csr; ++} ++ ++struct crypto_csr * crypto_csr_verify(const struct wpabuf *req) ++{ ++ /* future: look for alternatives to MBEDTLS_PRIVATE() access */ ++ ++ /* sole caller src/common/dpp_crypto.c:dpp_validate_csr() ++ * uses (mbedtls_x509_csr *) to obtain CSR_ATTR_CHALLENGE_PASSWORD ++ * so allocate different object (mbedtls_x509_csr *) and special-case ++ * object when used in crypto_csr_get_attribute() and when free()d in ++ * crypto_csr_deinit(). */ ++ ++ mbedtls_x509_csr *csr = os_malloc(sizeof(*csr)); ++ if (csr == NULL) ++ return NULL; ++ mbedtls_x509_csr_init(csr); ++ const mbedtls_md_info_t *md_info; ++ unsigned char digest[MBEDTLS_MD_MAX_SIZE]; ++ if (mbedtls_x509_csr_parse_der(csr,wpabuf_head(req),wpabuf_len(req))==0 ++ && (md_info=mbedtls_md_info_from_type(csr->MBEDTLS_PRIVATE(sig_md))) ++ != NULL ++ && mbedtls_md(md_info, csr->cri.p, csr->cri.len, digest) == 0) { ++ switch (mbedtls_pk_verify(&csr->pk,csr->MBEDTLS_PRIVATE(sig_md), ++ digest, mbedtls_md_get_size(md_info), ++ csr->MBEDTLS_PRIVATE(sig).p, ++ csr->MBEDTLS_PRIVATE(sig).len)) { ++ case 0: ++ /*case MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH:*//* XXX: allow? */ ++ return (struct crypto_csr *)((uintptr_t)csr | 1uL); ++ default: ++ break; ++ } ++ } ++ ++ mbedtls_x509_csr_free(csr); ++ os_free(csr); ++ return NULL; ++} ++ ++void crypto_csr_deinit(struct crypto_csr *csr) ++{ ++ if ((uintptr_t)csr & 1uL) { ++ csr = (struct crypto_csr *)((uintptr_t)csr & ~1uL); ++ mbedtls_x509_csr_free((mbedtls_x509_csr *)csr); ++ } ++ else ++ mbedtls_x509write_csr_free((mbedtls_x509write_csr *)csr); ++ os_free(csr); ++} ++ ++int crypto_csr_set_ec_public_key(struct crypto_csr *csr, ++ struct crypto_ec_key *key) ++{ ++ mbedtls_x509write_csr_set_key((mbedtls_x509write_csr *)csr, ++ (mbedtls_pk_context *)key); ++ return 0; ++} ++ ++int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type, ++ const char *name) ++{ ++ /* specialized for src/common/dpp_crypto.c */ ++ ++ /* sole caller src/common/dpp_crypto.c:dpp_build_csr() ++ * calls this function only once, using type == CSR_NAME_CN ++ * (If called more than once, this code would need to append ++ * components to the subject name, which we could do by ++ * appending to (mbedtls_x509write_csr *) private member ++ * mbedtls_asn1_named_data *MBEDTLS_PRIVATE(subject)) */ ++ ++ const char *label; ++ switch (type) { ++ case CSR_NAME_CN: label = "CN="; break; ++ case CSR_NAME_SN: label = "SN="; break; ++ case CSR_NAME_C: label = "C="; break; ++ case CSR_NAME_O: label = "O="; break; ++ case CSR_NAME_OU: label = "OU="; break; ++ default: return -1; ++ } ++ ++ size_t len = strlen(name); ++ struct wpabuf *buf = wpabuf_alloc(3+len+1); ++ if (buf == NULL) ++ return -1; ++ wpabuf_put_data(buf, label, strlen(label)); ++ wpabuf_put_data(buf, name, len+1); /*(include trailing '\0')*/ ++ /* Note: 'name' provided is set as given and should be backslash-escaped ++ * by caller when necessary, e.g. literal ',' which are not separating ++ * components should be backslash-escaped */ ++ ++ int ret = ++ mbedtls_x509write_csr_set_subject_name((mbedtls_x509write_csr *)csr, ++ wpabuf_head(buf)) ? -1 : 0; ++ wpabuf_free(buf); ++ return ret; ++} ++ ++/* OBJ_pkcs9_challengePassword 1 2 840 113549 1 9 7 */ ++static const char OBJ_pkcs9_challengePassword[] = MBEDTLS_OID_PKCS9 "\x07"; ++ ++int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr, ++ int attr_type, const u8 *value, size_t len) ++{ ++ /* specialized for src/common/dpp_crypto.c */ ++ /* sole caller src/common/dpp_crypto.c:dpp_build_csr() passes ++ * attr == CSR_ATTR_CHALLENGE_PASSWORD ++ * attr_type == ASN1_TAG_UTF8STRING */ ++ ++ const char *oid; ++ size_t oid_len; ++ switch (attr) { ++ case CSR_ATTR_CHALLENGE_PASSWORD: ++ oid = OBJ_pkcs9_challengePassword; ++ oid_len = sizeof(OBJ_pkcs9_challengePassword)-1; ++ break; ++ default: ++ return -1; ++ } ++ ++ #if 0 /*(incorrect; sets an extension, not an attribute)*/ ++ return mbedtls_x509write_csr_set_extension((mbedtls_x509write_csr *)csr, ++ oid, oid_len, ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ 0, /*(critical flag)*/ ++ #endif ++ value, len) ? -1 : 0; ++ #else ++ (void)oid; ++ (void)oid_len; ++ #endif ++ ++ /* mbedtls does not currently provide way to set an attribute in a CSR: ++ * https://github.com/Mbed-TLS/mbedtls/issues/4886 */ ++ wpa_printf(MSG_ERROR, ++ "mbedtls does not currently support setting challengePassword " ++ "attribute in CSR"); ++ return -1; ++} ++ ++const u8 * mbedtls_x509_csr_attr_oid_value(mbedtls_x509_csr *csr, ++ const char *oid, size_t oid_len, ++ size_t *vlen, int *vtype) ++{ ++ /* Note: mbedtls_x509_csr_parse_der() has parsed and validated CSR, ++ * so validation checks are not repeated here ++ * ++ * It would be nicer if (mbedtls_x509_csr *) had an mbedtls_x509_buf of ++ * Attributes (or at least a pointer) since mbedtls_x509_csr_parse_der() ++ * already parsed the rest of CertificationRequestInfo, some of which is ++ * repeated here to step to Attributes. Since csr->subject_raw.p points ++ * into csr->cri.p, which points into csr->raw.p, step over version and ++ * subject of CertificationRequestInfo (SEQUENCE) */ ++ unsigned char *p = csr->subject_raw.p + csr->subject_raw.len; ++ unsigned char *end = csr->cri.p + csr->cri.len, *ext; ++ size_t len; ++ ++ /* step over SubjectPublicKeyInfo */ ++ mbedtls_asn1_get_tag(&p, end, &len, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); ++ p += len; ++ ++ /* Attributes ++ * { ATTRIBUTE:IOSet } ::= SET OF { SEQUENCE { OID, value } } ++ */ ++ if (mbedtls_asn1_get_tag(&p, end, &len, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { ++ return NULL; ++ } ++ while (p < end) { ++ if (mbedtls_asn1_get_tag(&p, end, &len, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { ++ return NULL; ++ } ++ ext = p; ++ p += len; ++ ++ if (mbedtls_asn1_get_tag(&ext,end,&len,MBEDTLS_ASN1_OID) != 0) ++ return NULL; ++ if (oid_len != len || 0 != memcmp(ext, oid, oid_len)) ++ continue; ++ ++ /* found oid; return value */ ++ *vtype = *ext++; /* tag */ ++ return (mbedtls_asn1_get_len(&ext,end,vlen) == 0) ? ext : NULL; ++ } ++ ++ return NULL; ++} ++ ++const u8 * crypto_csr_get_attribute(struct crypto_csr *csr, ++ enum crypto_csr_attr attr, ++ size_t *len, int *type) ++{ ++ /* specialized for src/common/dpp_crypto.c */ ++ /* sole caller src/common/dpp_crypto.c:dpp_build_csr() passes ++ * attr == CSR_ATTR_CHALLENGE_PASSWORD */ ++ ++ const char *oid; ++ size_t oid_len; ++ switch (attr) { ++ case CSR_ATTR_CHALLENGE_PASSWORD: ++ oid = OBJ_pkcs9_challengePassword; ++ oid_len = sizeof(OBJ_pkcs9_challengePassword)-1; ++ break; ++ default: ++ return NULL; ++ } ++ ++ /* see crypto_csr_verify(); expecting (mbedtls_x509_csr *) tagged |=1 */ ++ if (!((uintptr_t)csr & 1uL)) ++ return NULL; ++ csr = (struct crypto_csr *)((uintptr_t)csr & ~1uL); ++ ++ return mbedtls_x509_csr_attr_oid_value((mbedtls_x509_csr *)csr, ++ oid, oid_len, len, type); ++} ++ ++struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, ++ struct crypto_ec_key *key, ++ enum crypto_hash_alg algo) ++{ ++ mbedtls_md_type_t sig_md; ++ switch (algo) { ++ #ifdef MBEDTLS_SHA256_C ++ case CRYPTO_HASH_ALG_SHA256: sig_md = MBEDTLS_MD_SHA256; break; ++ #endif ++ #ifdef MBEDTLS_SHA512_C ++ case CRYPTO_HASH_ALG_SHA384: sig_md = MBEDTLS_MD_SHA384; break; ++ case CRYPTO_HASH_ALG_SHA512: sig_md = MBEDTLS_MD_SHA512; break; ++ #endif ++ default: ++ return NULL; ++ } ++ mbedtls_x509write_csr_set_md_alg((mbedtls_x509write_csr *)csr, sig_md); ++ ++ #if 0 ++ unsigned char key_usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE ++ | MBEDTLS_X509_KU_KEY_CERT_SIGN; ++ if (mbedtls_x509write_csr_set_key_usage((mbedtls_x509write_csr *)csr, ++ key_usage)) ++ return NULL; ++ #endif ++ ++ #if 0 ++ unsigned char ns_cert_type = MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT ++ | MBEDTLS_X509_NS_CERT_TYPE_EMAIL; ++ if (mbedtls_x509write_csr_set_ns_cert_type((mbedtls_x509write_csr *)csr, ++ ns_cert_type)) ++ return NULL; ++ #endif ++ ++ #if 0 ++ /* mbedtls does not currently provide way to set an attribute in a CSR: ++ * https://github.com/Mbed-TLS/mbedtls/issues/4886 ++ * XXX: hwsim dpp_enterprise test fails due to this limitation. ++ * ++ * Current usage of this function is solely by dpp_build_csr(), ++ * so as a kludge, might consider custom (struct crypto_csr *) ++ * containing (mbedtls_x509write_csr *) and a list of attributes ++ * (i.e. challengePassword). Might have to totally reimplement ++ * mbedtls_x509write_csr_der(); underlying x509write_csr_der_internal() ++ * handles signing the CSR. (This is more work that appending an ++ * Attributes section to end of CSR and adjusting ASN.1 length of CSR.) ++ */ ++ #endif ++ ++ unsigned char buf[4096]; /* XXX: large enough? too large? */ ++ int len = mbedtls_x509write_csr_der((mbedtls_x509write_csr *)csr, ++ buf, sizeof(buf), ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg()); ++ if (len < 0) ++ return NULL; ++ /* Note: data is written at the end of the buffer! Use the ++ * return value to determine where you should start ++ * using the buffer */ ++ return wpabuf_alloc_copy(buf+sizeof(buf)-len, (size_t)len); ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_CSR */ ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_PKCS7 ++ ++#if 0 ++#include <mbedtls/pkcs7.h> /* PKCS7 is not currently supported in mbedtls */ ++#include <mbedtls/pem.h> ++#endif ++ ++struct wpabuf * crypto_pkcs7_get_certificates(const struct wpabuf *pkcs7) ++{ ++ /* PKCS7 is not currently supported in mbedtls */ ++ return NULL; ++ ++#if 0 ++ /* https://github.com/naynajain/mbedtls-1 branch: development-pkcs7 ++ * (??? potential future contribution to mbedtls ???) */ ++ ++ /* Note: PKCS7 signature *is not* verified by this function. ++ * The function interface does not provide for passing a certificate */ ++ ++ mbedtls_pkcs7 mpkcs7; ++ mbedtls_pkcs7_init(&mpkcs7); ++ int pkcs7_type = mbedtls_pkcs7_parse_der(wpabuf_head(pkcs7), ++ wpabuf_len(pkcs7), ++ &mpkcs7); ++ wpabuf *buf = NULL; ++ do { ++ if (pkcs7_type < 0) ++ break; ++ ++ /* src/common/dpp.c:dpp_parse_cred_dot1x() interested in certs ++ * for wpa_supplicant/dpp_supplicant.c:wpas_dpp_add_network() ++ * (? are adding certificate headers and footers desired ?) */ ++ ++ /* development-pkcs7 branch does not currently provide ++ * additional interfaces to retrieve the parsed data */ ++ ++ mbedtls_x509_crt *certs = ++ &mpkcs7.MBEDTLS_PRIVATE(signed_data).MBEDTLS_PRIVATE(certs); ++ int ncerts = ++ mpkcs7.MBEDTLS_PRIVATE(signed_data).MBEDTLS_PRIVATE(no_of_certs); ++ ++ /* allocate buffer for PEM (base64-encoded DER) ++ * plus header, footer, newlines, and some extra */ ++ buf = wpabuf_alloc((wpabuf_len(pkcs7)+2)/3*4 + ncerts*64); ++ if (buf == NULL) ++ break; ++ ++ #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" ++ #define PEM_END_CRT "-----END CERTIFICATE-----\n" ++ size_t olen; ++ for (int i = 0; i < ncerts; ++i) { ++ int ret = mbedtls_pem_write_buffer( ++ PEM_BEGIN_CRT, PEM_END_CRT, ++ certs[i].raw.p, certs[i].raw.len, ++ wpabuf_mhead(buf, 0), wpabuf_tailroom(buf), ++ &olen)); ++ if (ret == 0) ++ wpabuf_put(buf, olen); ++ } else { ++ if (ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) ++ ret = wpabuf_resize( ++ &buf,olen-wpabuf_tailroom(buf)); ++ if (ret == 0) { ++ --i;/*(adjust loop iterator for retry)*/ ++ continue; ++ } ++ wpabuf_free(buf); ++ buf = NULL; ++ break; ++ } ++ } ++ } while (0); ++ ++ mbedtls_pkcs7_free(&mpkcs7); ++ return buf; ++#endif ++} ++ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_PKCS7 */ ++ ++ ++#ifdef MBEDTLS_ARC4_C ++#include <mbedtls/arc4.h> ++int rc4_skip(const u8 *key, size_t keylen, size_t skip, ++ u8 *data, size_t data_len) ++{ ++ mbedtls_arc4_context ctx; ++ mbedtls_arc4_init(&ctx); ++ mbedtls_arc4_setup(&ctx, key, keylen); ++ ++ if (skip) { ++ /*(prefer [16] on ancient hardware with smaller cache lines)*/ ++ unsigned char skip_buf[64]; /*('skip' is generally small)*/ ++ /*os_memset(skip_buf, 0, sizeof(skip_buf));*/ /*(necessary?)*/ ++ size_t len; ++ do { ++ len = skip > sizeof(skip_buf) ? sizeof(skip_buf) : skip; ++ mbedtls_arc4_crypt(&ctx, len, skip_buf, skip_buf); ++ } while ((skip -= len)); ++ } ++ ++ int ret = mbedtls_arc4_crypt(&ctx, data_len, data, data); ++ mbedtls_arc4_free(&ctx); ++ return ret; ++} ++#endif ++ ++ ++/* duplicated in tls_mbedtls.c:tls_mbedtls_readfile()*/ ++__attribute_noinline__ ++static int crypto_mbedtls_readfile(const char *path, u8 **buf, size_t *n) ++{ ++ #if 0 /* #ifdef MBEDTLS_FS_IO */ ++ /*(includes +1 for '\0' needed by mbedtls PEM parsing funcs)*/ ++ if (mbedtls_pk_load_file(path, (unsigned char **)buf, n) != 0) { ++ wpa_printf(MSG_ERROR, "error: mbedtls_pk_load_file %s", path); ++ return -1; ++ } ++ #else ++ /*(use os_readfile() so that we can use os_free() ++ *(if we use mbedtls_pk_load_file() above, macros prevent calling free() ++ * directly #if defined(OS_REJECT_C_LIB_FUNCTIONS) and calling os_free() ++ * on buf aborts in tests if buf not allocated via os_malloc())*/ ++ *buf = (u8 *)os_readfile(path, n); ++ if (!*buf) { ++ wpa_printf(MSG_ERROR, "error: os_readfile %s", path); ++ return -1; ++ } ++ u8 *buf0 = os_realloc(*buf, *n+1); ++ if (!buf0) { ++ bin_clear_free(*buf, *n); ++ *buf = NULL; ++ return -1; ++ } ++ buf0[(*n)++] = '\0'; ++ *buf = buf0; ++ #endif ++ return 0; ++} ++ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_RSA ++#ifdef MBEDTLS_RSA_C ++ ++#include <mbedtls/pk.h> ++#include <mbedtls/rsa.h> ++ ++struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key) ++{ ++ /* mbedtls_pk_parse_keyfile() and mbedtls_pk_parse_public_keyfile() ++ * require #ifdef MBEDTLS_FS_IO in mbedtls library. Prefer to use ++ * crypto_mbedtls_readfile(), which wraps os_readfile() */ ++ u8 *data; ++ size_t len; ++ if (crypto_mbedtls_readfile(file, &data, &len) != 0) ++ return NULL; ++ ++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx)); ++ if (ctx == NULL) { ++ bin_clear_free(data, len); ++ return NULL; ++ } ++ mbedtls_pk_init(ctx); ++ ++ int rc; ++ rc = (private_key ++ ? mbedtls_pk_parse_key(ctx, data, len, NULL, 0 ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ ,mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg() ++ #endif ++ ) ++ : mbedtls_pk_parse_public_key(ctx, data, len)) == 0 ++ && mbedtls_pk_can_do(ctx, MBEDTLS_PK_RSA); ++ ++ bin_clear_free(data, len); ++ ++ if (rc) { ++ /* use MBEDTLS_RSA_PKCS_V21 padding for RSAES-OAEP */ ++ /* use MBEDTLS_MD_SHA256 for these hostap interfaces */ ++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++ /*(no return value in mbedtls 2.x)*/ ++ mbedtls_rsa_set_padding(mbedtls_pk_rsa(*ctx), ++ MBEDTLS_RSA_PKCS_V21, ++ MBEDTLS_MD_SHA256); ++ #else ++ if (mbedtls_rsa_set_padding(mbedtls_pk_rsa(*ctx), ++ MBEDTLS_RSA_PKCS_V21, ++ MBEDTLS_MD_SHA256) == 0) ++ #endif ++ return (struct crypto_rsa_key *)ctx; ++ } ++ ++ mbedtls_pk_free(ctx); ++ os_free(ctx); ++ return NULL; ++} ++ ++struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key, ++ const struct wpabuf *in) ++{ ++ mbedtls_rsa_context *pk_rsa = mbedtls_pk_rsa(*(mbedtls_pk_context*)key); ++ size_t olen = mbedtls_rsa_get_len(pk_rsa); ++ struct wpabuf *buf = wpabuf_alloc(olen); ++ if (buf == NULL) ++ return NULL; ++ ++ /* mbedtls_pk_encrypt() takes a few more hops to get to same func */ ++ if (mbedtls_rsa_rsaes_oaep_encrypt(pk_rsa, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg(), ++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++ MBEDTLS_RSA_PRIVATE, ++ #endif ++ NULL, 0, ++ wpabuf_len(in), wpabuf_head(in), ++ wpabuf_put(buf, olen)) == 0) { ++ return buf; ++ } ++ ++ wpabuf_clear_free(buf); ++ return NULL; ++} ++ ++struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key, ++ const struct wpabuf *in) ++{ ++ mbedtls_rsa_context *pk_rsa = mbedtls_pk_rsa(*(mbedtls_pk_context*)key); ++ size_t olen = mbedtls_rsa_get_len(pk_rsa); ++ struct wpabuf *buf = wpabuf_alloc(olen); ++ if (buf == NULL) ++ return NULL; ++ ++ /* mbedtls_pk_decrypt() takes a few more hops to get to same func */ ++ if (mbedtls_rsa_rsaes_oaep_decrypt(pk_rsa, ++ mbedtls_ctr_drbg_random, ++ crypto_mbedtls_ctr_drbg(), ++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++ MBEDTLS_RSA_PUBLIC, ++ #endif ++ NULL, 0, &olen, wpabuf_head(in), ++ wpabuf_mhead(buf), olen) == 0) { ++ wpabuf_put(buf, olen); ++ return buf; ++ } ++ ++ wpabuf_clear_free(buf); ++ return NULL; ++} ++ ++void crypto_rsa_key_free(struct crypto_rsa_key *key) ++{ ++ mbedtls_pk_free((mbedtls_pk_context *)key); ++ os_free(key); ++} ++ ++#endif /* MBEDTLS_RSA_C */ ++#endif /* CRYPTO_MBEDTLS_CRYPTO_RSA */ ++ ++#ifdef CRYPTO_MBEDTLS_CRYPTO_HPKE ++ ++struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id, ++ enum hpke_kdf_id kdf_id, ++ enum hpke_aead_id aead_id, ++ struct crypto_ec_key *peer_pub, ++ const u8 *info, size_t info_len, ++ const u8 *aad, size_t aad_len, ++ const u8 *pt, size_t pt_len) ++{ ++ /* not yet implemented */ ++ return NULL; ++} ++ ++struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id, ++ enum hpke_kdf_id kdf_id, ++ enum hpke_aead_id aead_id, ++ struct crypto_ec_key *own_priv, ++ const u8 *info, size_t info_len, ++ const u8 *aad, size_t aad_len, ++ const u8 *enc_ct, size_t enc_ct_len) ++{ ++ /* not yet implemented */ ++ return NULL; ++} ++ ++#endif +--- /dev/null ++++ b/src/crypto/tls_mbedtls.c +@@ -0,0 +1,3313 @@ ++/* ++ * SSL/TLS interface functions for mbed TLS ++ * ++ * SPDX-FileCopyrightText: 2022 Glenn Strauss <gstrauss@gluelogic.com> ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ * ++ * template: src/crypto/tls_none.c ++ * reference: src/crypto/tls_*.c ++ * ++ * Known Limitations: ++ * - no TLSv1.3 (not available in mbedtls 2.x; experimental in mbedtls 3.x) ++ * - no OCSP (not yet available in mbedtls) ++ * - mbedtls does not support all certificate encodings used by hwsim tests ++ * PCKS#5 v1.5 ++ * PCKS#12 ++ * DH DSA ++ * - EAP-FAST, EAP-TEAP session ticket support not implemented in tls_mbedtls.c ++ * - mbedtls does not currently provide way to set an attribute in a CSR ++ * https://github.com/Mbed-TLS/mbedtls/issues/4886 ++ * so tests/hwsim dpp_enterprise tests fail ++ * - DPP2 not supported ++ * PKCS#7 parsing is not supported in mbedtls ++ * See crypto_mbedtls.c:crypto_pkcs7_get_certificates() comments ++ * - DPP3 not supported ++ * hpke_base_seal() and hpke_base_seal() not implemented in crypto_mbedtls.c ++ * ++ * Status: ++ * - code written to be compatible with mbedtls 2.x and mbedtls 3.x ++ * (currently requires mbedtls >= 2.27.0 for mbedtls_mpi_random()) ++ * (currently requires mbedtls >= 2.18.0 for mbedtls_ssl_tls_prf()) ++ * - builds with tests/build/build-wpa_supplicant-mbedtls.config ++ * - passes all tests/ crypto module tests (incomplete coverage) ++ * ($ cd tests; make clean; make -j 4 run-tests CONFIG_TLS=mbedtls) ++ * - passes almost all tests/hwsim tests ++ * (hwsim tests skipped for missing features) ++ * ++ * RFE: ++ * - EAP-FAST, EAP-TEAP session ticket support not implemented in tls_mbedtls.c ++ * - client/server session resumption, and/or save client session ticket ++ */ ++ ++#include "includes.h" ++#include "common.h" ++ ++#include <mbedtls/version.h> ++#include <mbedtls/ctr_drbg.h> ++#include <mbedtls/error.h> ++#include <mbedtls/oid.h> ++#include <mbedtls/pem.h> ++#include <mbedtls/platform.h> /* mbedtls_calloc() mbedtls_free() */ ++#include <mbedtls/platform_util.h> /* mbedtls_platform_zeroize() */ ++#include <mbedtls/ssl.h> ++#include <mbedtls/ssl_ticket.h> ++#include <mbedtls/x509.h> ++#include <mbedtls/x509_crt.h> ++ ++#if MBEDTLS_VERSION_NUMBER >= 0x02040000 /* mbedtls 2.4.0 */ ++#include <mbedtls/net_sockets.h> ++#else ++#include <mbedtls/net.h> ++#endif ++ ++#ifndef MBEDTLS_PRIVATE ++#define MBEDTLS_PRIVATE(x) x ++#endif ++ ++#if MBEDTLS_VERSION_NUMBER < 0x03020000 /* mbedtls 3.2.0 */ ++#define mbedtls_ssl_get_ciphersuite_id_from_ssl(ssl) \ ++ ((ssl)->MBEDTLS_PRIVATE(session) \ ++ ?(ssl)->MBEDTLS_PRIVATE(session)->MBEDTLS_PRIVATE(ciphersuite) \ ++ : 0) ++#define mbedtls_ssl_ciphersuite_get_name(info) \ ++ (info)->MBEDTLS_PRIVATE(name) ++#endif ++ ++#include "crypto.h" /* sha256_vector() */ ++#include "tls.h" ++ ++#ifndef SHA256_DIGEST_LENGTH ++#define SHA256_DIGEST_LENGTH 32 ++#endif ++ ++#ifndef MBEDTLS_EXPKEY_FIXED_SECRET_LEN ++#define MBEDTLS_EXPKEY_FIXED_SECRET_LEN 48 ++#endif ++ ++#ifndef MBEDTLS_EXPKEY_RAND_LEN ++#define MBEDTLS_EXPKEY_RAND_LEN 32 ++#endif ++ ++#if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++static mbedtls_ssl_export_keys_t tls_connection_export_keys_cb; ++#elif MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++static mbedtls_ssl_export_keys_ext_t tls_connection_export_keys_cb; ++#else /*(not implemented; return error)*/ ++#define mbedtls_ssl_tls_prf(a,b,c,d,e,f,g,h) (-1) ++typedef mbedtls_tls_prf_types int; ++#endif ++ ++ ++/* hostapd/wpa_supplicant provides forced_memzero(), ++ * but prefer mbedtls_platform_zeroize() */ ++#define forced_memzero(ptr,sz) mbedtls_platform_zeroize(ptr,sz) ++ ++ ++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) \ ++ || defined(EAP_TEAP) || defined(EAP_SERVER_TEAP) ++#ifdef MBEDTLS_SSL_SESSION_TICKETS ++#ifdef MBEDTLS_SSL_TICKET_C ++#define TLS_MBEDTLS_SESSION_TICKETS ++#if defined(EAP_TEAP) || defined(EAP_SERVER_TEAP) ++#define TLS_MBEDTLS_EAP_TEAP ++#endif ++#if !defined(CONFIG_FIPS) /* EAP-FAST keys cannot be exported in FIPS mode */ ++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) ++#define TLS_MBEDTLS_EAP_FAST ++#endif ++#endif ++#endif ++#endif ++#endif ++ ++ ++struct tls_conf { ++ mbedtls_ssl_config conf; ++ ++ unsigned int verify_peer:1; ++ unsigned int verify_depth0_only:1; ++ unsigned int check_crl:2; /*(needs :2 bits for 0, 1, 2)*/ ++ unsigned int check_crl_strict:1; /*(needs :1 bit for 0, 1)*/ ++ unsigned int ca_cert_probe:1; ++ unsigned int has_ca_cert:1; ++ unsigned int has_client_cert:1; ++ unsigned int has_private_key:1; ++ unsigned int suiteb128:1; ++ unsigned int suiteb192:1; ++ mbedtls_x509_crl *crl; ++ mbedtls_x509_crt ca_cert; ++ mbedtls_x509_crt client_cert; ++ mbedtls_pk_context private_key; ++ ++ uint32_t refcnt; ++ ++ unsigned int flags; ++ char *subject_match; ++ char *altsubject_match; ++ char *suffix_match; ++ char *domain_match; ++ char *check_cert_subject; ++ u8 ca_cert_hash[SHA256_DIGEST_LENGTH]; ++ ++ int *ciphersuites; /* list of ciphersuite ids for mbedtls_ssl_config */ ++#if MBEDTLS_VERSION_NUMBER < 0x03010000 /* mbedtls 3.1.0 */ ++ mbedtls_ecp_group_id *curves; ++#else ++ uint16_t *curves; /* list of curve ids for mbedtls_ssl_config */ ++#endif ++}; ++ ++ ++struct tls_global { ++ struct tls_conf *tls_conf; ++ char *ocsp_stapling_response; ++ mbedtls_ctr_drbg_context *ctr_drbg; /*(see crypto_mbedtls.c)*/ ++ #ifdef MBEDTLS_SSL_SESSION_TICKETS ++ mbedtls_ssl_ticket_context ticket_ctx; ++ #endif ++ char *ca_cert_file; ++ struct os_reltime crl_reload_previous; ++ unsigned int crl_reload_interval; ++ uint32_t refcnt; ++ struct tls_config init_conf; ++}; ++ ++static struct tls_global tls_ctx_global; ++ ++ ++struct tls_connection { ++ struct tls_conf *tls_conf; ++ struct wpabuf *push_buf; ++ struct wpabuf *pull_buf; ++ size_t pull_buf_offset; ++ ++ unsigned int established:1; ++ unsigned int resumed:1; ++ unsigned int verify_peer:1; ++ unsigned int is_server:1; ++ ++ mbedtls_ssl_context ssl; ++ ++ mbedtls_tls_prf_types tls_prf_type; ++ size_t expkey_keyblock_size; ++ size_t expkey_secret_len; ++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++ unsigned char expkey_secret[MBEDTLS_EXPKEY_FIXED_SECRET_LEN]; ++ #else ++ unsigned char expkey_secret[MBEDTLS_MD_MAX_SIZE]; ++ #endif ++ unsigned char expkey_randbytes[MBEDTLS_EXPKEY_RAND_LEN*2]; ++ ++ int read_alerts, write_alerts, failed; ++ ++ #ifdef TLS_MBEDTLS_SESSION_TICKETS ++ tls_session_ticket_cb session_ticket_cb; ++ void *session_ticket_cb_ctx; ++ unsigned char *clienthello_session_ticket; ++ size_t clienthello_session_ticket_len; ++ #endif ++ char *peer_subject; /* peer subject info for authenticated peer */ ++ struct wpabuf *success_data; ++}; ++ ++ ++#ifndef __has_attribute ++#define __has_attribute(x) 0 ++#endif ++ ++#ifndef __GNUC_PREREQ ++#define __GNUC_PREREQ(maj,min) 0 ++#endif ++ ++#ifndef __attribute_cold__ ++#if __has_attribute(cold) \ ++ || __GNUC_PREREQ(4,3) ++#define __attribute_cold__ __attribute__((__cold__)) ++#else ++#define __attribute_cold__ ++#endif ++#endif ++ ++#ifndef __attribute_noinline__ ++#if __has_attribute(noinline) \ ++ || __GNUC_PREREQ(3,1) ++#define __attribute_noinline__ __attribute__((__noinline__)) ++#else ++#define __attribute_noinline__ ++#endif ++#endif ++ ++ ++__attribute_cold__ ++__attribute_noinline__ ++static void emsg(int level, const char * const msg) ++{ ++ wpa_printf(level, "MTLS: %s", msg); ++} ++ ++ ++__attribute_cold__ ++__attribute_noinline__ ++static void emsgrc(int level, const char * const msg, int rc) ++{ ++ #ifdef MBEDTLS_ERROR_C ++ /* error logging convenience function that decodes mbedtls result codes */ ++ char buf[256]; ++ mbedtls_strerror(rc, buf, sizeof(buf)); ++ wpa_printf(level, "MTLS: %s: %s (-0x%04x)", msg, buf, -rc); ++ #else ++ wpa_printf(level, "MTLS: %s: (-0x%04x)", msg, -rc); ++ #endif ++} ++ ++ ++#define elog(rc, msg) emsgrc(MSG_ERROR, (msg), (rc)) ++#define ilog(rc, msg) emsgrc(MSG_INFO, (msg), (rc)) ++ ++ ++struct tls_conf * tls_conf_init(void *tls_ctx) ++{ ++ struct tls_conf *tls_conf = os_zalloc(sizeof(*tls_conf)); ++ if (tls_conf == NULL) ++ return NULL; ++ tls_conf->refcnt = 1; ++ ++ mbedtls_ssl_config_init(&tls_conf->conf); ++ mbedtls_ssl_conf_rng(&tls_conf->conf, ++ mbedtls_ctr_drbg_random, tls_ctx_global.ctr_drbg); ++ mbedtls_x509_crt_init(&tls_conf->ca_cert); ++ mbedtls_x509_crt_init(&tls_conf->client_cert); ++ mbedtls_pk_init(&tls_conf->private_key); ++ ++ return tls_conf; ++} ++ ++ ++void tls_conf_deinit(struct tls_conf *tls_conf) ++{ ++ if (tls_conf == NULL || --tls_conf->refcnt != 0) ++ return; ++ ++ mbedtls_x509_crt_free(&tls_conf->ca_cert); ++ mbedtls_x509_crt_free(&tls_conf->client_cert); ++ if (tls_conf->crl) { ++ mbedtls_x509_crl_free(tls_conf->crl); ++ os_free(tls_conf->crl); ++ } ++ mbedtls_pk_free(&tls_conf->private_key); ++ mbedtls_ssl_config_free(&tls_conf->conf); ++ os_free(tls_conf->curves); ++ os_free(tls_conf->ciphersuites); ++ os_free(tls_conf->subject_match); ++ os_free(tls_conf->altsubject_match); ++ os_free(tls_conf->suffix_match); ++ os_free(tls_conf->domain_match); ++ os_free(tls_conf->check_cert_subject); ++ os_free(tls_conf); ++} ++ ++ ++mbedtls_ctr_drbg_context * crypto_mbedtls_ctr_drbg(void); /*(not in header)*/ ++ ++__attribute_cold__ ++void * tls_init(const struct tls_config *conf) ++{ ++ /* RFE: review struct tls_config *conf (different from tls_conf) */ ++ ++ if (++tls_ctx_global.refcnt > 1) ++ return &tls_ctx_global; ++ ++ tls_ctx_global.ctr_drbg = crypto_mbedtls_ctr_drbg(); ++ #ifdef MBEDTLS_SSL_SESSION_TICKETS ++ mbedtls_ssl_ticket_init(&tls_ctx_global.ticket_ctx); ++ mbedtls_ssl_ticket_setup(&tls_ctx_global.ticket_ctx, ++ mbedtls_ctr_drbg_random, ++ tls_ctx_global.ctr_drbg, ++ MBEDTLS_CIPHER_AES_256_GCM, ++ 43200); /* ticket timeout: 12 hours */ ++ #endif ++ /* copy struct for future use */ ++ tls_ctx_global.init_conf = *conf; ++ if (conf->openssl_ciphers) ++ tls_ctx_global.init_conf.openssl_ciphers = ++ os_strdup(conf->openssl_ciphers); ++ ++ tls_ctx_global.crl_reload_interval = conf->crl_reload_interval; ++ os_get_reltime(&tls_ctx_global.crl_reload_previous); ++ ++ return &tls_ctx_global; ++} ++ ++ ++__attribute_cold__ ++void tls_deinit(void *tls_ctx) ++{ ++ if (tls_ctx == NULL || --tls_ctx_global.refcnt != 0) ++ return; ++ ++ tls_conf_deinit(tls_ctx_global.tls_conf); ++ os_free(tls_ctx_global.ca_cert_file); ++ os_free(tls_ctx_global.ocsp_stapling_response); ++ char *openssl_ciphers; /*(allocated in tls_init())*/ ++ *(const char **)&openssl_ciphers = ++ tls_ctx_global.init_conf.openssl_ciphers; ++ os_free(openssl_ciphers); ++ #ifdef MBEDTLS_SSL_SESSION_TICKETS ++ mbedtls_ssl_ticket_free(&tls_ctx_global.ticket_ctx); ++ #endif ++ os_memset(&tls_ctx_global, 0, sizeof(tls_ctx_global)); ++} ++ ++ ++int tls_get_errors(void *tls_ctx) ++{ ++ return 0; ++} ++ ++ ++static void tls_connection_deinit_expkey(struct tls_connection *conn) ++{ ++ conn->tls_prf_type = 0; /* MBEDTLS_SSL_TLS_PRF_NONE; */ ++ conn->expkey_keyblock_size = 0; ++ conn->expkey_secret_len = 0; ++ forced_memzero(conn->expkey_secret, sizeof(conn->expkey_secret)); ++ forced_memzero(conn->expkey_randbytes, sizeof(conn->expkey_randbytes)); ++} ++ ++ ++#ifdef TLS_MBEDTLS_SESSION_TICKETS ++void tls_connection_deinit_clienthello_session_ticket(struct tls_connection *conn) ++{ ++ if (conn->clienthello_session_ticket) { ++ mbedtls_platform_zeroize(conn->clienthello_session_ticket, ++ conn->clienthello_session_ticket_len); ++ mbedtls_free(conn->clienthello_session_ticket); ++ conn->clienthello_session_ticket = NULL; ++ conn->clienthello_session_ticket_len = 0; ++ } ++} ++#endif ++ ++ ++void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) ++{ ++ if (conn == NULL) ++ return; ++ ++ #if 0 /*(good intention, but never sent since we destroy self below)*/ ++ if (conn->established) ++ mbedtls_ssl_close_notify(&conn->ssl); ++ #endif ++ ++ if (conn->tls_prf_type) ++ tls_connection_deinit_expkey(conn); ++ ++ #ifdef TLS_MBEDTLS_SESSION_TICKETS ++ if (conn->clienthello_session_ticket) ++ tls_connection_deinit_clienthello_session_ticket(conn); ++ #endif ++ ++ os_free(conn->peer_subject); ++ wpabuf_free(conn->success_data); ++ wpabuf_free(conn->push_buf); ++ wpabuf_free(conn->pull_buf); ++ mbedtls_ssl_free(&conn->ssl); ++ tls_conf_deinit(conn->tls_conf); ++ os_free(conn); ++} ++ ++ ++static void tls_mbedtls_refresh_crl(void); ++static int tls_mbedtls_ssl_setup(struct tls_connection *conn); ++ ++struct tls_connection * tls_connection_init(void *tls_ctx) ++{ ++ struct tls_connection *conn = os_zalloc(sizeof(*conn)); ++ if (conn == NULL) ++ return NULL; ++ ++ mbedtls_ssl_init(&conn->ssl); ++ ++ conn->tls_conf = tls_ctx_global.tls_conf; /*(inherit global conf, if set)*/ ++ if (conn->tls_conf) { ++ ++conn->tls_conf->refcnt; ++ /* check for CRL refresh if inheriting from global config */ ++ tls_mbedtls_refresh_crl(); ++ ++ conn->verify_peer = conn->tls_conf->verify_peer; ++ if (tls_mbedtls_ssl_setup(conn) != 0) { ++ tls_connection_deinit(&tls_ctx_global, conn); ++ return NULL; ++ } ++ } ++ ++ return conn; ++} ++ ++ ++int tls_connection_established(void *tls_ctx, struct tls_connection *conn) ++{ ++ return conn ? conn->established : 0; ++} ++ ++ ++__attribute_noinline__ ++char * tls_mbedtls_peer_serial_num(const mbedtls_x509_crt *crt, char *serial_num, size_t len) ++{ ++ /* mbedtls_x509_serial_gets() inefficiently formats to hex separated by ++ * colons, so generate the hex serial number here. The func ++ * wpa_snprintf_hex_uppercase() is similarly inefficient. */ ++ size_t i = 0; /* skip leading 0's per Distinguished Encoding Rules (DER) */ ++ while (i < crt->serial.len && crt->serial.p[i] == 0) ++i; ++ if (i == crt->serial.len) --i; ++ ++ const unsigned char *s = crt->serial.p + i; ++ const size_t e = (crt->serial.len - i) * 2; ++ if (e >= len) ++ return NULL; ++ #if 0 ++ wpa_snprintf_hex_uppercase(serial_num, len, s, crt->serial.len-i); ++ #else ++ for (i = 0; i < e; i+=2, ++s) { ++ serial_num[i+0] = "0123456789ABCDEF"[(*s >> 4)]; ++ serial_num[i+1] = "0123456789ABCDEF"[(*s & 0xF)]; ++ } ++ serial_num[e] = '\0'; ++ #endif ++ return serial_num; ++} ++ ++ ++char * tls_connection_peer_serial_num(void *tls_ctx, ++ struct tls_connection *conn) ++{ ++ const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&conn->ssl); ++ if (crt == NULL) ++ return NULL; ++ size_t len = crt->serial.len * 2 + 1; ++ char *serial_num = os_malloc(len); ++ if (!serial_num) ++ return NULL; ++ return tls_mbedtls_peer_serial_num(crt, serial_num, len); ++} ++ ++ ++static void tls_pull_buf_reset(struct tls_connection *conn); ++ ++int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) ++{ ++ /* Note: this function called from eap_peer_tls_reauth_init() ++ * for session resumption, not for connection shutdown */ ++ ++ if (conn == NULL) ++ return -1; ++ ++ tls_pull_buf_reset(conn); ++ wpabuf_free(conn->push_buf); ++ conn->push_buf = NULL; ++ conn->established = 0; ++ conn->resumed = 0; ++ if (conn->tls_prf_type) ++ tls_connection_deinit_expkey(conn); ++ ++ /* RFE: prepare for session resumption? (see doc in crypto/tls.h) */ ++ ++ return mbedtls_ssl_session_reset(&conn->ssl); ++} ++ ++ ++static int tls_wpabuf_resize_put_data(struct wpabuf **buf, ++ const unsigned char *data, size_t dlen) ++{ ++ if (wpabuf_resize(buf, dlen) < 0) ++ return 0; ++ wpabuf_put_data(*buf, data, dlen); ++ return 1; ++} ++ ++ ++static int tls_pull_buf_append(struct tls_connection *conn, ++ const struct wpabuf *in_data) ++{ ++ /*(interface does not lend itself to move semantics)*/ ++ return tls_wpabuf_resize_put_data(&conn->pull_buf, ++ wpabuf_head(in_data), ++ wpabuf_len(in_data)); ++} ++ ++ ++static void tls_pull_buf_reset(struct tls_connection *conn) ++{ ++ /*(future: might consider reusing conn->pull_buf)*/ ++ wpabuf_free(conn->pull_buf); ++ conn->pull_buf = NULL; ++ conn->pull_buf_offset = 0; ++} ++ ++ ++__attribute_cold__ ++static void tls_pull_buf_discard(struct tls_connection *conn, const char *func) ++{ ++ size_t discard = wpabuf_len(conn->pull_buf) - conn->pull_buf_offset; ++ if (discard) ++ wpa_printf(MSG_DEBUG, ++ "%s - %zu bytes remaining in pull_buf; discarding", ++ func, discard); ++ tls_pull_buf_reset(conn); ++} ++ ++ ++static int tls_pull_func(void *ptr, unsigned char *buf, size_t len) ++{ ++ struct tls_connection *conn = (struct tls_connection *) ptr; ++ if (conn->pull_buf == NULL) ++ return MBEDTLS_ERR_SSL_WANT_READ; ++ const size_t dlen = wpabuf_len(conn->pull_buf) - conn->pull_buf_offset; ++ if (dlen == 0) ++ return MBEDTLS_ERR_SSL_WANT_READ; ++ ++ if (len > dlen) ++ len = dlen; ++ os_memcpy(buf, wpabuf_head(conn->pull_buf)+conn->pull_buf_offset, len); ++ ++ if (len == dlen) { ++ tls_pull_buf_reset(conn); ++ /*wpa_printf(MSG_DEBUG, "%s - emptied pull_buf", __func__);*/ ++ } ++ else { ++ conn->pull_buf_offset += len; ++ /*wpa_printf(MSG_DEBUG, "%s - %zu bytes remaining in pull_buf", ++ __func__, dlen - len);*/ ++ } ++ return (int)len; ++} ++ ++ ++static int tls_push_func(void *ptr, const unsigned char *buf, size_t len) ++{ ++ struct tls_connection *conn = (struct tls_connection *) ptr; ++ return tls_wpabuf_resize_put_data(&conn->push_buf, buf, len) ++ ? (int)len ++ : MBEDTLS_ERR_SSL_ALLOC_FAILED; ++} ++ ++ ++static int ++tls_mbedtls_verify_cb (void *arg, mbedtls_x509_crt *crt, int depth, uint32_t *flags); ++ ++ ++static int tls_mbedtls_ssl_setup(struct tls_connection *conn) ++{ ++ #if 0 ++ /* mbedtls_ssl_setup() must be called only once */ ++ /* If this func might be called multiple times (e.g. via set_params), ++ * then we should set a flag in conn that ssl was initialized */ ++ if (conn->ssl_is_init) { ++ mbedtls_ssl_free(&conn->ssl); ++ mbedtls_ssl_init(&conn->ssl); ++ } ++ #endif ++ ++ int ret = mbedtls_ssl_setup(&conn->ssl, &conn->tls_conf->conf); ++ if (ret != 0) { ++ elog(ret, "mbedtls_ssl_setup"); ++ return -1; ++ } ++ ++ mbedtls_ssl_set_bio(&conn->ssl, conn, tls_push_func, tls_pull_func, NULL); ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ mbedtls_ssl_set_export_keys_cb( ++ &conn->ssl, tls_connection_export_keys_cb, conn); ++ #elif MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++ mbedtls_ssl_conf_export_keys_ext_cb( ++ &conn->tls_conf->conf, tls_connection_export_keys_cb, conn); ++ #endif ++ if (conn->verify_peer) ++ mbedtls_ssl_set_verify(&conn->ssl, tls_mbedtls_verify_cb, conn); ++ ++ return 0; ++} ++ ++ ++static int tls_mbedtls_data_is_pem(const u8 *data) ++{ ++ return (NULL != os_strstr((char *)data, "-----")); ++} ++ ++ ++static void tls_mbedtls_set_allowed_tls_vers(struct tls_conf *tls_conf, ++ mbedtls_ssl_config *conf) ++{ ++ #if !defined(MBEDTLS_SSL_PROTO_TLS1_3) ++ tls_conf->flags |= TLS_CONN_DISABLE_TLSv1_3; ++ #endif ++ ++ /* unconditionally require TLSv1.2+ for TLS_CONN_SUITEB */ ++ if (tls_conf->flags & TLS_CONN_SUITEB) { ++ tls_conf->flags |= TLS_CONN_DISABLE_TLSv1_0; ++ tls_conf->flags |= TLS_CONN_DISABLE_TLSv1_1; ++ } ++ ++ const unsigned int flags = tls_conf->flags; ++ ++ /* attempt to map flags to min and max TLS protocol version */ ++ ++ int min = (flags & TLS_CONN_DISABLE_TLSv1_0) ++ ? (flags & TLS_CONN_DISABLE_TLSv1_1) ++ ? (flags & TLS_CONN_DISABLE_TLSv1_2) ++ ? (flags & TLS_CONN_DISABLE_TLSv1_3) ++ ? 4 ++ : 3 ++ : 2 ++ : 1 ++ : 0; ++ ++ int max = (flags & TLS_CONN_DISABLE_TLSv1_3) ++ ? (flags & TLS_CONN_DISABLE_TLSv1_2) ++ ? (flags & TLS_CONN_DISABLE_TLSv1_1) ++ ? (flags & TLS_CONN_DISABLE_TLSv1_0) ++ ? -1 ++ : 0 ++ : 1 ++ : 2 ++ : 3; ++ ++ if ((flags & TLS_CONN_ENABLE_TLSv1_2) && min > 2) min = 2; ++ if ((flags & TLS_CONN_ENABLE_TLSv1_1) && min > 1) min = 1; ++ if ((flags & TLS_CONN_ENABLE_TLSv1_0) && min > 0) min = 0; ++ if (max < min) { ++ emsg(MSG_ERROR, "invalid tls_disable_tlsv* params; ignoring"); ++ return; ++ } ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ /* mbed TLS 3.0.0 removes support for protocols < TLSv1.2 */ ++ if (min < 2 || max < 2) { ++ emsg(MSG_ERROR, "invalid tls_disable_tlsv* params; ignoring"); ++ if (min < 2) min = 2; ++ if (max < 2) max = 2; ++ } ++ #endif ++ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */ ++ /* MBEDTLS_SSL_VERSION_TLS1_2 = 0x0303 *//*!< (D)TLS 1.2 */ ++ /* MBEDTLS_SSL_VERSION_TLS1_3 = 0x0304 *//*!< (D)TLS 1.3 */ ++ min = (min == 2) ? MBEDTLS_SSL_VERSION_TLS1_2 : MBEDTLS_SSL_VERSION_TLS1_3; ++ max = (max == 2) ? MBEDTLS_SSL_VERSION_TLS1_2 : MBEDTLS_SSL_VERSION_TLS1_3; ++ mbedtls_ssl_conf_min_tls_version(conf, min); ++ mbedtls_ssl_conf_max_tls_version(conf, max); ++ #else ++ #ifndef MBEDTLS_SSL_MINOR_VERSION_4 ++ if (min == 3) min = 2; ++ if (max == 3) max = 2; ++ #endif ++ /* MBEDTLS_SSL_MINOR_VERSION_0 0 *//*!< SSL v3.0 */ ++ /* MBEDTLS_SSL_MINOR_VERSION_1 1 *//*!< TLS v1.0 */ ++ /* MBEDTLS_SSL_MINOR_VERSION_2 2 *//*!< TLS v1.1 */ ++ /* MBEDTLS_SSL_MINOR_VERSION_3 3 *//*!< TLS v1.2 */ ++ /* MBEDTLS_SSL_MINOR_VERSION_4 4 *//*!< TLS v1.3 */ ++ mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, min+1); ++ mbedtls_ssl_conf_max_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, max+1); ++ #endif ++} ++ ++ ++__attribute_noinline__ ++static int tls_mbedtls_readfile(const char *path, u8 **buf, size_t *n); ++ ++ ++static int ++tls_mbedtls_set_dhparams(struct tls_conf *tls_conf, const char *dh_file) ++{ ++ size_t len; ++ u8 *data; ++ if (tls_mbedtls_readfile(dh_file, &data, &len)) ++ return 0; ++ ++ /* parse only if DH parameters if in PEM format */ ++ if (tls_mbedtls_data_is_pem(data) ++ && NULL == os_strstr((char *)data, "-----BEGIN DH PARAMETERS-----")) { ++ if (os_strstr((char *)data, "-----BEGIN DSA PARAMETERS-----")) ++ wpa_printf(MSG_WARNING, "DSA parameters not handled (%s)", dh_file); ++ else ++ wpa_printf(MSG_WARNING, "unexpected DH param content (%s)",dh_file); ++ forced_memzero(data, len); ++ os_free(data); ++ return 0; ++ } ++ ++ /* mbedtls_dhm_parse_dhm() expects "-----BEGIN DH PARAMETERS-----" if PEM */ ++ mbedtls_dhm_context dhm; ++ mbedtls_dhm_init(&dhm); ++ int rc = mbedtls_dhm_parse_dhm(&dhm, data, len); ++ if (0 == rc) ++ rc = mbedtls_ssl_conf_dh_param_ctx(&tls_conf->conf, &dhm); ++ if (0 != rc) ++ elog(rc, dh_file); ++ mbedtls_dhm_free(&dhm); ++ ++ forced_memzero(data, len); ++ os_free(data); ++ return (0 == rc); ++} ++ ++ ++/* reference: lighttpd src/mod_mbedtls.c:mod_mbedtls_ssl_append_curve() ++ * (same author: gstrauss@gluelogic.com; same license: BSD-3-Clause) */ ++#if MBEDTLS_VERSION_NUMBER < 0x03010000 /* mbedtls 3.1.0 */ ++static int ++tls_mbedtls_append_curve (mbedtls_ecp_group_id *ids, int nids, int idsz, const mbedtls_ecp_group_id id) ++{ ++ if (1 >= idsz - (nids + 1)) { ++ emsg(MSG_ERROR, "error: too many curves during list expand"); ++ return -1; ++ } ++ ids[++nids] = id; ++ return nids; ++} ++ ++ ++static int ++tls_mbedtls_set_curves(struct tls_conf *tls_conf, const char *curvelist) ++{ ++ mbedtls_ecp_group_id ids[512]; ++ int nids = -1; ++ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1); ++ const mbedtls_ecp_curve_info * const curve_info = mbedtls_ecp_curve_list(); ++ ++ for (const char *e = curvelist-1; e; ) { ++ const char * const n = e+1; ++ e = os_strchr(n, ':'); ++ size_t len = e ? (size_t)(e - n) : os_strlen(n); ++ mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE; ++ switch (len) { ++ case 5: ++ if (0 == os_memcmp("P-521", n, 5)) ++ grp_id = MBEDTLS_ECP_DP_SECP521R1; ++ else if (0 == os_memcmp("P-384", n, 5)) ++ grp_id = MBEDTLS_ECP_DP_SECP384R1; ++ else if (0 == os_memcmp("P-256", n, 5)) ++ grp_id = MBEDTLS_ECP_DP_SECP256R1; ++ break; ++ case 6: ++ if (0 == os_memcmp("BP-521", n, 6)) ++ grp_id = MBEDTLS_ECP_DP_BP512R1; ++ else if (0 == os_memcmp("BP-384", n, 6)) ++ grp_id = MBEDTLS_ECP_DP_BP384R1; ++ else if (0 == os_memcmp("BP-256", n, 6)) ++ grp_id = MBEDTLS_ECP_DP_BP256R1; ++ break; ++ default: ++ break; ++ } ++ if (grp_id != MBEDTLS_ECP_DP_NONE) { ++ nids = tls_mbedtls_append_curve(ids, nids, idsz, grp_id); ++ if (-1 == nids) return 0; ++ continue; ++ } ++ /* similar to mbedtls_ecp_curve_info_from_name() */ ++ const mbedtls_ecp_curve_info *info; ++ for (info = curve_info; info->grp_id != MBEDTLS_ECP_DP_NONE; ++info) { ++ if (0 == os_strncmp(info->name, n, len) && info->name[len] == '\0') ++ break; ++ } ++ if (info->grp_id == MBEDTLS_ECP_DP_NONE) { ++ wpa_printf(MSG_ERROR, "MTLS: unrecognized curve: %.*s",(int)len,n); ++ return 0; ++ } ++ ++ nids = tls_mbedtls_append_curve(ids, nids, idsz, info->grp_id); ++ if (-1 == nids) return 0; ++ } ++ ++ /* mod_openssl configures "prime256v1" if curve list not specified, ++ * but mbedtls provides a list of supported curves if not explicitly set */ ++ if (-1 == nids) return 1; /* empty list; no-op */ ++ ++ ids[++nids] = MBEDTLS_ECP_DP_NONE; /* terminate list */ ++ ++nids; ++ ++ /* curves list must be persistent for lifetime of mbedtls_ssl_config */ ++ tls_conf->curves = os_malloc(nids * sizeof(mbedtls_ecp_group_id)); ++ if (tls_conf->curves == NULL) ++ return 0; ++ os_memcpy(tls_conf->curves, ids, nids * sizeof(mbedtls_ecp_group_id)); ++ ++ mbedtls_ssl_conf_curves(&tls_conf->conf, tls_conf->curves); ++ return 1; ++} ++#else ++static int ++tls_mbedtls_append_curve (uint16_t *ids, int nids, int idsz, const uint16_t id) ++{ ++ if (1 >= idsz - (nids + 1)) { ++ emsg(MSG_ERROR, "error: too many curves during list expand"); ++ return -1; ++ } ++ ids[++nids] = id; ++ return nids; ++} ++ ++ ++static int ++tls_mbedtls_set_curves(struct tls_conf *tls_conf, const char *curvelist) ++{ ++ /* TLS Supported Groups (renamed from "EC Named Curve Registry") ++ * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 ++ */ ++ uint16_t ids[512]; ++ int nids = -1; ++ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1); ++ const mbedtls_ecp_curve_info * const curve_info = mbedtls_ecp_curve_list(); ++ ++ for (const char *e = curvelist-1; e; ) { ++ const char * const n = e+1; ++ e = os_strchr(n, ':'); ++ size_t len = e ? (size_t)(e - n) : os_strlen(n); ++ uint16_t tls_id = 0; ++ switch (len) { ++ case 5: ++ if (0 == os_memcmp("P-521", n, 5)) ++ tls_id = 25; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_SECP521R1 */ ++ else if (0 == os_memcmp("P-384", n, 5)) ++ tls_id = 24; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_SECP384R1 */ ++ else if (0 == os_memcmp("P-256", n, 5)) ++ tls_id = 23; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_SECP256R1 */ ++ break; ++ case 6: ++ if (0 == os_memcmp("BP-521", n, 6)) ++ tls_id = 28; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_BP512R1 */ ++ else if (0 == os_memcmp("BP-384", n, 6)) ++ tls_id = 27; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_BP384R1 */ ++ else if (0 == os_memcmp("BP-256", n, 6)) ++ tls_id = 26; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_BP256R1 */ ++ break; ++ default: ++ break; ++ } ++ if (tls_id != 0) { ++ nids = tls_mbedtls_append_curve(ids, nids, idsz, tls_id); ++ if (-1 == nids) return 0; ++ continue; ++ } ++ /* similar to mbedtls_ecp_curve_info_from_name() */ ++ const mbedtls_ecp_curve_info *info; ++ for (info = curve_info; info->tls_id != 0; ++info) { ++ if (0 == os_strncmp(info->name, n, len) && info->name[len] == '\0') ++ break; ++ } ++ if (info->tls_id == 0) { ++ wpa_printf(MSG_ERROR, "MTLS: unrecognized curve: %.*s",(int)len,n); ++ return 0; ++ } ++ ++ nids = tls_mbedtls_append_curve(ids, nids, idsz, info->tls_id); ++ if (-1 == nids) return 0; ++ } ++ ++ /* mod_openssl configures "prime256v1" if curve list not specified, ++ * but mbedtls provides a list of supported curves if not explicitly set */ ++ if (-1 == nids) return 1; /* empty list; no-op */ ++ ++ ids[++nids] = 0; /* terminate list */ ++ ++nids; ++ ++ /* curves list must be persistent for lifetime of mbedtls_ssl_config */ ++ tls_conf->curves = os_malloc(nids * sizeof(uint16_t)); ++ if (tls_conf->curves == NULL) ++ return 0; ++ os_memcpy(tls_conf->curves, ids, nids * sizeof(uint16_t)); ++ ++ mbedtls_ssl_conf_groups(&tls_conf->conf, tls_conf->curves); ++ return 1; ++} ++#endif /* MBEDTLS_VERSION_NUMBER >= 0x03010000 */ /* mbedtls 3.1.0 */ ++ ++ ++/* data copied from lighttpd src/mod_mbedtls.c (BSD-3-Clause) */ ++static const int suite_AES_256_ephemeral[] = { ++ /* All AES-256 ephemeral suites */ ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 ++}; ++ ++/* data copied from lighttpd src/mod_mbedtls.c (BSD-3-Clause) */ ++static const int suite_AES_128_ephemeral[] = { ++ /* All AES-128 ephemeral suites */ ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 ++}; ++ ++/* data copied from lighttpd src/mod_mbedtls.c (BSD-3-Clause) */ ++/* HIGH cipher list (mapped from openssl list to mbedtls) */ ++static const int suite_HIGH[] = { ++ MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, ++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, ++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, ++ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, ++ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, ++ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, ++ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, ++ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, ++ MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_RSA_WITH_AES_256_CCM, ++ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, ++ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, ++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, ++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, ++ MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_RSA_WITH_AES_128_CCM, ++ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, ++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, ++ MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256, ++ MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, ++ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, ++ MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, ++ MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, ++ MBEDTLS_TLS_PSK_WITH_AES_256_CCM, ++ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, ++ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, ++ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, ++ MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, ++ MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384, ++ MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, ++ MBEDTLS_TLS_PSK_WITH_AES_128_CCM, ++ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, ++ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, ++ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, ++ MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, ++ MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 ++}; ++ ++ ++__attribute_noinline__ ++static int ++tls_mbedtls_append_ciphersuite (int *ids, int nids, int idsz, const int *x, int xsz) ++{ ++ if (xsz >= idsz - (nids + 1)) { ++ emsg(MSG_ERROR, "error: too many ciphers during list expand"); ++ return -1; ++ } ++ ++ for (int i = 0; i < xsz; ++i) ++ ids[++nids] = x[i]; ++ ++ return nids; ++} ++ ++ ++static int ++tls_mbedtls_translate_ciphername(int id, char *buf, size_t buflen) ++{ ++ const mbedtls_ssl_ciphersuite_t *info = ++ mbedtls_ssl_ciphersuite_from_id(id); ++ if (info == NULL) ++ return 0; ++ const char *name = mbedtls_ssl_ciphersuite_get_name(info); ++ const size_t len = os_strlen(name); ++ if (len == 7 && 0 == os_memcmp(name, "unknown", 7)) ++ return 0; ++ if (len >= buflen) ++ return 0; ++ os_strlcpy(buf, name, buflen); ++ ++ /* attempt to translate mbedtls string to openssl string ++ * (some heuristics; incomplete) */ ++ size_t i = 0, j = 0; ++ if (buf[0] == 'T') { ++ if (os_strncmp(buf, "TLS1-3-", 7) == 0) { ++ buf[3] = '-'; ++ j = 4; /* remove "1-3" from "TLS1-3-" prefix */ ++ i = 7; ++ } ++ else if (os_strncmp(buf, "TLS-", 4) == 0) ++ i = 4; /* remove "TLS-" prefix */ ++ } ++ for (; buf[i]; ++i) { ++ if (buf[i] == '-') { ++ if (i >= 3) { ++ if (0 == os_memcmp(buf+i-3, "AES", 3)) ++ continue; /* "AES-" -> "AES" */ ++ } ++ if (i >= 4) { ++ if (0 == os_memcmp(buf+i-4, "WITH", 4)) { ++ j -= 4; /* remove "WITH-" */ ++ continue; ++ } ++ } ++ } ++ buf[j++] = buf[i]; ++ } ++ buf[j] = '\0'; ++ ++ return j; ++} ++ ++ ++__attribute_noinline__ ++static int ++tls_mbedtls_set_ciphersuites(struct tls_conf *tls_conf, int *ids, int nids) ++{ ++ /* ciphersuites list must be persistent for lifetime of mbedtls_ssl_config*/ ++ os_free(tls_conf->ciphersuites); ++ tls_conf->ciphersuites = os_malloc(nids * sizeof(int)); ++ if (tls_conf->ciphersuites == NULL) ++ return 0; ++ os_memcpy(tls_conf->ciphersuites, ids, nids * sizeof(int)); ++ mbedtls_ssl_conf_ciphersuites(&tls_conf->conf, tls_conf->ciphersuites); ++ return 1; ++} ++ ++ ++static int ++tls_mbedtls_set_ciphers(struct tls_conf *tls_conf, const char *ciphers) ++{ ++ char buf[64]; ++ int ids[512]; ++ int nids = -1; ++ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1); ++ const char *next; ++ size_t blen, clen; ++ do { ++ next = os_strchr(ciphers, ':'); ++ clen = next ? (size_t)(next - ciphers) : os_strlen(ciphers); ++ if (!clen) ++ continue; ++ ++ /* special-case a select set of openssl group names for hwsim tests */ ++ /* (review; remove excess code if tests are not run for non-OpenSSL?) */ ++ if (clen == 9 && os_memcmp(ciphers, "SUITEB192", 9) == 0) { ++ static int ssl_preset_suiteb192_ciphersuites[] = { ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, ++ 0 ++ }; ++ return tls_mbedtls_set_ciphersuites(tls_conf, ++ ssl_preset_suiteb192_ciphersuites, ++ 2); ++ } ++ if (clen == 9 && os_memcmp(ciphers, "SUITEB128", 9) == 0) { ++ static int ssl_preset_suiteb128_ciphersuites[] = { ++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ++ 0 ++ }; ++ return tls_mbedtls_set_ciphersuites(tls_conf, ++ ssl_preset_suiteb128_ciphersuites, ++ 2); ++ } ++ if (clen == 7 && os_memcmp(ciphers, "DEFAULT", 7) == 0) ++ continue; ++ if (clen == 6 && os_memcmp(ciphers, "AES128", 6) == 0) { ++ nids = tls_mbedtls_append_ciphersuite(ids, nids, idsz, ++ suite_AES_128_ephemeral, ++ (int)ARRAY_SIZE(suite_AES_128_ephemeral)); ++ if (nids == -1) ++ return 0; ++ continue; ++ } ++ if (clen == 6 && os_memcmp(ciphers, "AES256", 6) == 0) { ++ nids = tls_mbedtls_append_ciphersuite(ids, nids, idsz, ++ suite_AES_256_ephemeral, ++ (int)ARRAY_SIZE(suite_AES_256_ephemeral)); ++ if (nids == -1) ++ return 0; ++ continue; ++ } ++ if (clen == 4 && os_memcmp(ciphers, "HIGH", 4) == 0) { ++ nids = tls_mbedtls_append_ciphersuite(ids, nids, idsz, suite_HIGH, ++ (int)ARRAY_SIZE(suite_HIGH)); ++ if (nids == -1) ++ return 0; ++ continue; ++ } ++ /* ignore anonymous cipher group names (?not supported by mbedtls?) */ ++ if (clen == 4 && os_memcmp(ciphers, "!ADH", 4) == 0) ++ continue; ++ if (clen == 6 && os_memcmp(ciphers, "-aECDH", 6) == 0) ++ continue; ++ if (clen == 7 && os_memcmp(ciphers, "-aECDSA", 7) == 0) ++ continue; ++ ++ /* attempt to match mbedtls cipher names ++ * nb: does not support openssl group names or list manipulation syntax ++ * (alt: could copy almost 1200 lines (!!!) of lighttpd mod_mbedtls.c ++ * mod_mbedtls_ssl_conf_ciphersuites() to translate strings) ++ * note: not efficient to rewrite list for each ciphers entry, ++ * but this code is expected to run only at startup ++ */ ++ const int *list = mbedtls_ssl_list_ciphersuites(); ++ for (; *list; ++list) { ++ blen = tls_mbedtls_translate_ciphername(*list,buf,sizeof(buf)); ++ if (!blen) ++ continue; ++ ++ /* matching heuristics additional to translate_ciphername above */ ++ if (blen == clen+4) { ++ char *cbc = os_strstr(buf, "CBC-"); ++ if (cbc) { ++ os_memmove(cbc, cbc+4, blen-(cbc+4-buf)+1); /*(w/ '\0')*/ ++ blen -= 4; ++ } ++ } ++ if (blen >= clen && os_memcmp(ciphers, buf, clen) == 0 ++ && (blen == clen ++ || (blen == clen+7 && os_memcmp(buf+clen, "-SHA256", 7)))) { ++ if (1 >= idsz - (nids + 1)) { ++ emsg(MSG_ERROR, ++ "error: too many ciphers during list expand"); ++ return 0; ++ } ++ ids[++nids] = *list; ++ break; ++ } ++ } ++ if (*list == 0) { ++ wpa_printf(MSG_ERROR, ++ "MTLS: unrecognized cipher: %.*s", (int)clen, ciphers); ++ return 0; ++ } ++ } while ((ciphers = next ? next+1 : NULL)); ++ ++ if (-1 == nids) return 1; /* empty list; no-op */ ++ ++ ids[++nids] = 0; /* terminate list */ ++ ++nids; ++ ++ return tls_mbedtls_set_ciphersuites(tls_conf, ids, nids); ++} ++ ++ ++__attribute_noinline__ ++static int tls_mbedtls_set_item(char **config_item, const char *item) ++{ ++ os_free(*config_item); ++ *config_item = NULL; ++ return item ? (*config_item = os_strdup(item)) != NULL : 1; ++} ++ ++ ++static int tls_connection_set_subject_match(struct tls_conf *tls_conf, ++ const struct tls_connection_params *params) ++{ ++ int rc = 1; ++ rc &= tls_mbedtls_set_item(&tls_conf->subject_match, ++ params->subject_match); ++ rc &= tls_mbedtls_set_item(&tls_conf->altsubject_match, ++ params->altsubject_match); ++ rc &= tls_mbedtls_set_item(&tls_conf->suffix_match, ++ params->suffix_match); ++ rc &= tls_mbedtls_set_item(&tls_conf->domain_match, ++ params->domain_match); ++ rc &= tls_mbedtls_set_item(&tls_conf->check_cert_subject, ++ params->check_cert_subject); ++ return rc; ++} ++ ++ ++/* duplicated in crypto_mbedtls.c:crypto_mbedtls_readfile()*/ ++__attribute_noinline__ ++static int tls_mbedtls_readfile(const char *path, u8 **buf, size_t *n) ++{ ++ #if 0 /* #ifdef MBEDTLS_FS_IO */ ++ /*(includes +1 for '\0' needed by mbedtls PEM parsing funcs)*/ ++ if (mbedtls_pk_load_file(path, (unsigned char **)buf, n) != 0) { ++ wpa_printf(MSG_ERROR, "error: mbedtls_pk_load_file %s", path); ++ return -1; ++ } ++ #else ++ /*(use os_readfile() so that we can use os_free() ++ *(if we use mbedtls_pk_load_file() above, macros prevent calling free() ++ * directly #if defined(OS_REJECT_C_LIB_FUNCTIONS) and calling os_free() ++ * on buf aborts in tests if buf not allocated via os_malloc())*/ ++ *buf = (u8 *)os_readfile(path, n); ++ if (!*buf) { ++ wpa_printf(MSG_ERROR, "error: os_readfile %s", path); ++ return -1; ++ } ++ u8 *buf0 = os_realloc(*buf, *n+1); ++ if (!buf0) { ++ bin_clear_free(*buf, *n); ++ *buf = NULL; ++ return -1; ++ } ++ buf0[(*n)++] = '\0'; ++ *buf = buf0; ++ #endif ++ return 0; ++} ++ ++ ++static int tls_mbedtls_set_crl(struct tls_conf *tls_conf, const u8 *data, size_t len) ++{ ++ /* do not use mbedtls_x509_crl_parse() on PEM unless it contains CRL */ ++ if (len && data[len-1] == '\0' ++ && NULL == os_strstr((const char *)data,"-----BEGIN X509 CRL-----") ++ && tls_mbedtls_data_is_pem(data)) ++ return 0; ++ ++ mbedtls_x509_crl crl; ++ mbedtls_x509_crl_init(&crl); ++ int rc = mbedtls_x509_crl_parse(&crl, data, len); ++ if (rc < 0) { ++ mbedtls_x509_crl_free(&crl); ++ return rc == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ? 0 : rc; ++ } ++ ++ mbedtls_x509_crl *crl_new = os_malloc(sizeof(crl)); ++ if (crl_new == NULL) { ++ mbedtls_x509_crl_free(&crl); ++ return MBEDTLS_ERR_X509_ALLOC_FAILED; ++ } ++ os_memcpy(crl_new, &crl, sizeof(crl)); ++ ++ mbedtls_x509_crl *crl_old = tls_conf->crl; ++ tls_conf->crl = crl_new; ++ if (crl_old) { ++ mbedtls_x509_crl_free(crl_old); ++ os_free(crl_old); ++ } ++ return 0; ++} ++ ++ ++static int tls_mbedtls_set_ca(struct tls_conf *tls_conf, u8 *data, size_t len) ++{ ++ /* load crt struct onto stack and then copy into tls_conf in ++ * order to preserve existing tls_conf value if error occurs ++ * ++ * hostapd is not threaded, or else should allocate memory and swap in ++ * pointer reduce race condition. (If threaded, would also need to ++ * keep reference count of use to avoid freeing while still in use.) */ ++ ++ mbedtls_x509_crt crt; ++ mbedtls_x509_crt_init(&crt); ++ int rc = mbedtls_x509_crt_parse(&crt, data, len); ++ if (rc < 0) { ++ mbedtls_x509_crt_free(&crt); ++ return rc; ++ } ++ ++ mbedtls_x509_crt_free(&tls_conf->ca_cert); ++ os_memcpy(&tls_conf->ca_cert, &crt, sizeof(crt)); ++ return 0; ++} ++ ++ ++static int tls_mbedtls_set_ca_and_crl(struct tls_conf *tls_conf, const char *ca_cert_file) ++{ ++ size_t len; ++ u8 *data; ++ if (tls_mbedtls_readfile(ca_cert_file, &data, &len)) ++ return -1; ++ ++ int rc; ++ if (0 == (rc = tls_mbedtls_set_ca(tls_conf, data, len)) ++ && (!tls_mbedtls_data_is_pem(data) /*skip parse for CRL if not PEM*/ ++ || 0 == (rc = tls_mbedtls_set_crl(tls_conf, data, len)))) { ++ mbedtls_ssl_conf_ca_chain(&tls_conf->conf, ++ &tls_conf->ca_cert, ++ tls_conf->crl); ++ } ++ else { ++ elog(rc, __func__); ++ emsg(MSG_ERROR, ca_cert_file); ++ } ++ ++ forced_memzero(data, len); ++ os_free(data); ++ return rc; ++} ++ ++ ++static void tls_mbedtls_refresh_crl(void) ++{ ++ /* check for CRL refresh ++ * continue even if error occurs; continue with previous cert, CRL */ ++ unsigned int crl_reload_interval = tls_ctx_global.crl_reload_interval; ++ const char *ca_cert_file = tls_ctx_global.ca_cert_file; ++ if (!crl_reload_interval || !ca_cert_file) ++ return; ++ ++ struct os_reltime *previous = &tls_ctx_global.crl_reload_previous; ++ struct os_reltime now; ++ if (os_get_reltime(&now) != 0 ++ || !os_reltime_expired(&now, previous, crl_reload_interval)) ++ return; ++ ++ /* Note: modifying global state is not thread-safe ++ * if in use by existing connections ++ * ++ * src/utils/os.h does not provide a portable stat() ++ * or else it would be a good idea to check mtime and size, ++ * and avoid reloading if file has not changed */ ++ ++ if (tls_mbedtls_set_ca_and_crl(tls_ctx_global.tls_conf, ca_cert_file) == 0) ++ *previous = now; ++} ++ ++ ++static int tls_mbedtls_set_ca_cert(struct tls_conf *tls_conf, ++ const struct tls_connection_params *params) ++{ ++ if (params->ca_cert) { ++ if (os_strncmp(params->ca_cert, "probe://", 8) == 0) { ++ tls_conf->ca_cert_probe = 1; ++ tls_conf->has_ca_cert = 1; ++ return 0; ++ } ++ ++ if (os_strncmp(params->ca_cert, "hash://", 7) == 0) { ++ const char *pos = params->ca_cert + 7; ++ if (os_strncmp(pos, "server/sha256/", 14) != 0) { ++ emsg(MSG_ERROR, "unsupported ca_cert hash value"); ++ return -1; ++ } ++ pos += 14; ++ if (os_strlen(pos) != SHA256_DIGEST_LENGTH*2) { ++ emsg(MSG_ERROR, "unexpected ca_cert hash length"); ++ return -1; ++ } ++ if (hexstr2bin(pos, tls_conf->ca_cert_hash, ++ SHA256_DIGEST_LENGTH) < 0) { ++ emsg(MSG_ERROR, "invalid ca_cert hash value"); ++ return -1; ++ } ++ emsg(MSG_DEBUG, "checking only server certificate match"); ++ tls_conf->verify_depth0_only = 1; ++ tls_conf->has_ca_cert = 1; ++ return 0; ++ } ++ ++ if (tls_mbedtls_set_ca_and_crl(tls_conf, params->ca_cert) != 0) ++ return -1; ++ } ++ if (params->ca_cert_blob) { ++ size_t len = params->ca_cert_blob_len; ++ int is_pem = tls_mbedtls_data_is_pem(params->ca_cert_blob); ++ if (len && params->ca_cert_blob[len-1] != '\0' && is_pem) ++ ++len; /*(include '\0' in len for PEM)*/ ++ int ret = mbedtls_x509_crt_parse(&tls_conf->ca_cert, ++ params->ca_cert_blob, len); ++ if (ret != 0) { ++ elog(ret, "mbedtls_x509_crt_parse"); ++ return -1; ++ } ++ if (is_pem) { /*(ca_cert_blob in DER format contains ca cert only)*/ ++ ret = tls_mbedtls_set_crl(tls_conf, params->ca_cert_blob, len); ++ if (ret != 0) { ++ elog(ret, "mbedtls_x509_crl_parse"); ++ return -1; ++ } ++ } ++ } ++ ++ if (mbedtls_x509_time_is_future(&tls_conf->ca_cert.valid_from) ++ || mbedtls_x509_time_is_past(&tls_conf->ca_cert.valid_to)) { ++ emsg(MSG_WARNING, "ca_cert expired or not yet valid"); ++ if (params->ca_cert) ++ emsg(MSG_WARNING, params->ca_cert); ++ } ++ ++ tls_conf->has_ca_cert = 1; ++ return 0; ++} ++ ++ ++static int tls_mbedtls_set_certs(struct tls_conf *tls_conf, ++ const struct tls_connection_params *params) ++{ ++ int ret; ++ ++ if (params->ca_cert || params->ca_cert_blob) { ++ if (tls_mbedtls_set_ca_cert(tls_conf, params) != 0) ++ return -1; ++ } ++ else if (params->ca_path) { ++ emsg(MSG_INFO, "ca_path support not implemented"); ++ return -1; ++ } ++ ++ if (!tls_conf->has_ca_cert) ++ mbedtls_ssl_conf_authmode(&tls_conf->conf, MBEDTLS_SSL_VERIFY_NONE); ++ else { ++ /* Initial setting: REQUIRED for client, OPTIONAL for server ++ * (see also tls_connection_set_verify()) */ ++ tls_conf->verify_peer = (tls_ctx_global.tls_conf == NULL); ++ int authmode = tls_conf->verify_peer ++ ? MBEDTLS_SSL_VERIFY_REQUIRED ++ : MBEDTLS_SSL_VERIFY_OPTIONAL; ++ mbedtls_ssl_conf_authmode(&tls_conf->conf, authmode); ++ mbedtls_ssl_conf_ca_chain(&tls_conf->conf, ++ &tls_conf->ca_cert, ++ tls_conf->crl); ++ ++ if (!tls_connection_set_subject_match(tls_conf, params)) ++ return -1; ++ } ++ ++ if (params->client_cert2) /*(yes, server_cert2 in msg below)*/ ++ emsg(MSG_INFO, "server_cert2 support not implemented"); ++ ++ if (params->client_cert) { ++ size_t len; ++ u8 *data; ++ if (tls_mbedtls_readfile(params->client_cert, &data, &len)) ++ return -1; ++ ret = mbedtls_x509_crt_parse(&tls_conf->client_cert, data, len); ++ forced_memzero(data, len); ++ os_free(data); ++ } ++ if (params->client_cert_blob) { ++ size_t len = params->client_cert_blob_len; ++ if (len && params->client_cert_blob[len-1] != '\0' ++ && tls_mbedtls_data_is_pem(params->client_cert_blob)) ++ ++len; /*(include '\0' in len for PEM)*/ ++ ret = mbedtls_x509_crt_parse(&tls_conf->client_cert, ++ params->client_cert_blob, len); ++ } ++ if (params->client_cert || params->client_cert_blob) { ++ if (ret < 0) { ++ elog(ret, "mbedtls_x509_crt_parse"); ++ if (params->client_cert) ++ emsg(MSG_ERROR, params->client_cert); ++ return -1; ++ } ++ if (mbedtls_x509_time_is_future(&tls_conf->client_cert.valid_from) ++ || mbedtls_x509_time_is_past(&tls_conf->client_cert.valid_to)) { ++ emsg(MSG_WARNING, "cert expired or not yet valid"); ++ if (params->client_cert) ++ emsg(MSG_WARNING, params->client_cert); ++ } ++ tls_conf->has_client_cert = 1; ++ } ++ ++ if (params->private_key || params->private_key_blob) { ++ size_t len = params->private_key_blob_len; ++ u8 *data; ++ *(const u8 **)&data = params->private_key_blob; ++ if (len && data[len-1] != '\0' && tls_mbedtls_data_is_pem(data)) ++ ++len; /*(include '\0' in len for PEM)*/ ++ if (params->private_key ++ && tls_mbedtls_readfile(params->private_key, &data, &len)) { ++ return -1; ++ } ++ const char *pwd = params->private_key_passwd; ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ ret = mbedtls_pk_parse_key(&tls_conf->private_key, ++ data, len, ++ (const unsigned char *)pwd, ++ pwd ? os_strlen(pwd) : 0, ++ mbedtls_ctr_drbg_random, ++ tls_ctx_global.ctr_drbg); ++ #else ++ ret = mbedtls_pk_parse_key(&tls_conf->private_key, ++ data, len, ++ (const unsigned char *)pwd, ++ pwd ? os_strlen(pwd) : 0); ++ #endif ++ if (params->private_key) { ++ forced_memzero(data, len); ++ os_free(data); ++ } ++ if (ret < 0) { ++ elog(ret, "mbedtls_pk_parse_key"); ++ return -1; ++ } ++ tls_conf->has_private_key = 1; ++ } ++ ++ if (tls_conf->has_client_cert && tls_conf->has_private_key) { ++ ret = mbedtls_ssl_conf_own_cert( ++ &tls_conf->conf, &tls_conf->client_cert, &tls_conf->private_key); ++ if (ret < 0) { ++ elog(ret, "mbedtls_ssl_conf_own_cert"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++/* mbedtls_x509_crt_profile_suiteb plus rsa_min_bitlen 2048 */ ++/* (reference: see also mbedtls_x509_crt_profile_next) */ ++/* ??? should permit SHA-512, too, and additional curves ??? */ ++static const mbedtls_x509_crt_profile tls_mbedtls_crt_profile_suiteb128 = ++{ ++ /* Only SHA-256 and 384 */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), ++ /* Only ECDSA */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) | ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ), ++#if defined(MBEDTLS_ECP_C) ++ /* Only NIST P-256 and P-384 */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), ++#else ++ 0, ++#endif ++ 2048, ++}; ++ ++ ++/* stricter than mbedtls_x509_crt_profile_suiteb */ ++/* (reference: see also mbedtls_x509_crt_profile_next) */ ++/* ??? should permit SHA-512, too, and additional curves ??? */ ++static const mbedtls_x509_crt_profile tls_mbedtls_crt_profile_suiteb192 = ++{ ++ /* Only SHA-384 */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), ++ /* Only ECDSA */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) | ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ), ++#if defined(MBEDTLS_ECP_C) ++ /* Only NIST P-384 */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), ++#else ++ 0, ++#endif ++ 3072, ++}; ++ ++ ++/* stricter than mbedtls_x509_crt_profile_suiteb except allow any PK alg */ ++/* (reference: see also mbedtls_x509_crt_profile_next) */ ++/* ??? should permit SHA-512, too, and additional curves ??? */ ++static const mbedtls_x509_crt_profile tls_mbedtls_crt_profile_suiteb192_anypk = ++{ ++ /* Only SHA-384 */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), ++ 0xFFFFFFF, /* Any PK alg */ ++#if defined(MBEDTLS_ECP_C) ++ /* Only NIST P-384 */ ++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), ++#else ++ 0, ++#endif ++ 3072, ++}; ++ ++ ++static int tls_mbedtls_set_params(struct tls_conf *tls_conf, ++ const struct tls_connection_params *params) ++{ ++ tls_conf->flags = params->flags; ++ ++ if (tls_conf->flags & TLS_CONN_REQUIRE_OCSP_ALL) { ++ emsg(MSG_INFO, "ocsp=3 not supported"); ++ return -1; ++ } ++ ++ if (tls_conf->flags & TLS_CONN_REQUIRE_OCSP) { ++ emsg(MSG_INFO, "ocsp not supported"); ++ return -1; ++ } ++ ++ int suiteb128 = 0; ++ int suiteb192 = 0; ++ if (params->openssl_ciphers) { ++ if (os_strcmp(params->openssl_ciphers, "SUITEB192") == 0) { ++ suiteb192 = 1; ++ tls_conf->flags |= TLS_CONN_SUITEB; ++ } ++ if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) { ++ suiteb128 = 1; ++ tls_conf->flags |= TLS_CONN_SUITEB; ++ } ++ } ++ ++ int ret = mbedtls_ssl_config_defaults( ++ &tls_conf->conf, tls_ctx_global.tls_conf ? MBEDTLS_SSL_IS_SERVER ++ : MBEDTLS_SSL_IS_CLIENT, ++ MBEDTLS_SSL_TRANSPORT_STREAM, ++ (tls_conf->flags & TLS_CONN_SUITEB) ? MBEDTLS_SSL_PRESET_SUITEB ++ : MBEDTLS_SSL_PRESET_DEFAULT); ++ if (ret != 0) { ++ elog(ret, "mbedtls_ssl_config_defaults"); ++ return -1; ++ } ++ ++ if (suiteb128) { ++ mbedtls_ssl_conf_cert_profile(&tls_conf->conf, ++ &tls_mbedtls_crt_profile_suiteb128); ++ mbedtls_ssl_conf_dhm_min_bitlen(&tls_conf->conf, 2048); ++ } ++ else if (suiteb192) { ++ mbedtls_ssl_conf_cert_profile(&tls_conf->conf, ++ &tls_mbedtls_crt_profile_suiteb192); ++ mbedtls_ssl_conf_dhm_min_bitlen(&tls_conf->conf, 3072); ++ } ++ else if (tls_conf->flags & TLS_CONN_SUITEB) { ++ /* treat as suiteb192 while allowing any PK algorithm */ ++ mbedtls_ssl_conf_cert_profile(&tls_conf->conf, ++ &tls_mbedtls_crt_profile_suiteb192_anypk); ++ mbedtls_ssl_conf_dhm_min_bitlen(&tls_conf->conf, 3072); ++ } ++ ++ tls_mbedtls_set_allowed_tls_vers(tls_conf, &tls_conf->conf); ++ ret = tls_mbedtls_set_certs(tls_conf, params); ++ if (ret != 0) ++ return -1; ++ ++ if (params->dh_file ++ && !tls_mbedtls_set_dhparams(tls_conf, params->dh_file)) { ++ return -1; ++ } ++ ++ if (params->openssl_ecdh_curves ++ && !tls_mbedtls_set_curves(tls_conf, params->openssl_ecdh_curves)) { ++ return -1; ++ } ++ ++ if (params->openssl_ciphers) { ++ if (!tls_mbedtls_set_ciphers(tls_conf, params->openssl_ciphers)) ++ return -1; ++ } ++ else if (tls_conf->flags & TLS_CONN_SUITEB) { ++ /* special-case a select set of ciphers for hwsim tests */ ++ if (!tls_mbedtls_set_ciphers(tls_conf, ++ (tls_conf->flags & TLS_CONN_SUITEB_NO_ECDH) ++ ? "DHE-RSA-AES256-GCM-SHA384" ++ : "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384")) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, ++ const struct tls_connection_params *params) ++{ ++ if (conn == NULL || params == NULL) ++ return -1; ++ ++ tls_conf_deinit(conn->tls_conf); ++ struct tls_conf *tls_conf = conn->tls_conf = tls_conf_init(tls_ctx); ++ if (tls_conf == NULL) ++ return -1; ++ ++ if (tls_ctx_global.tls_conf) { ++ tls_conf->check_crl = tls_ctx_global.tls_conf->check_crl; ++ tls_conf->check_crl_strict = tls_ctx_global.tls_conf->check_crl_strict; ++ /*(tls_openssl.c inherits check_cert_subject from global conf)*/ ++ if (tls_ctx_global.tls_conf->check_cert_subject) { ++ tls_conf->check_cert_subject = ++ os_strdup(tls_ctx_global.tls_conf->check_cert_subject); ++ if (tls_conf->check_cert_subject == NULL) ++ return -1; ++ } ++ } ++ ++ if (tls_mbedtls_set_params(tls_conf, params) != 0) ++ return -1; ++ conn->verify_peer = tls_conf->verify_peer; ++ ++ return tls_mbedtls_ssl_setup(conn); ++} ++ ++ ++#ifdef TLS_MBEDTLS_SESSION_TICKETS ++ ++static int tls_mbedtls_clienthello_session_ticket_prep (struct tls_connection *conn, ++ const u8 *data, size_t len) ++{ ++ if (conn->tls_conf->flags & TLS_CONN_DISABLE_SESSION_TICKET) ++ return -1; ++ if (conn->clienthello_session_ticket) ++ tls_connection_deinit_clienthello_session_ticket(conn); ++ if (len) { ++ conn->clienthello_session_ticket = mbedtls_calloc(1, len); ++ if (conn->clienthello_session_ticket == NULL) ++ return -1; ++ conn->clienthello_session_ticket_len = len; ++ os_memcpy(conn->clienthello_session_ticket, data, len); ++ } ++ return 0; ++} ++ ++ ++static void tls_mbedtls_clienthello_session_ticket_set (struct tls_connection *conn) ++{ ++ mbedtls_ssl_session *sess = conn->ssl.MBEDTLS_PRIVATE(session_negotiate); ++ if (sess->MBEDTLS_PRIVATE(ticket)) { ++ mbedtls_platform_zeroize(sess->MBEDTLS_PRIVATE(ticket), ++ sess->MBEDTLS_PRIVATE(ticket_len)); ++ mbedtls_free(sess->MBEDTLS_PRIVATE(ticket)); ++ } ++ sess->MBEDTLS_PRIVATE(ticket) = conn->clienthello_session_ticket; ++ sess->MBEDTLS_PRIVATE(ticket_len) = conn->clienthello_session_ticket_len; ++ sess->MBEDTLS_PRIVATE(ticket_lifetime) = 86400;/* XXX: can hint be 0? */ ++ ++ conn->clienthello_session_ticket = NULL; ++ conn->clienthello_session_ticket_len = 0; ++} ++ ++ ++static int tls_mbedtls_ssl_ticket_write(void *p_ticket, ++ const mbedtls_ssl_session *session, ++ unsigned char *start, ++ const unsigned char *end, ++ size_t *tlen, ++ uint32_t *lifetime) ++{ ++ struct tls_connection *conn = p_ticket; ++ if (conn && conn->session_ticket_cb) { ++ /* see tls_mbedtls_clienthello_session_ticket_prep() */ ++ /* see tls_mbedtls_clienthello_session_ticket_set() */ ++ return 0; ++ } ++ ++ return mbedtls_ssl_ticket_write(&tls_ctx_global.ticket_ctx, ++ session, start, end, tlen, lifetime); ++} ++ ++ ++static int tls_mbedtls_ssl_ticket_parse(void *p_ticket, ++ mbedtls_ssl_session *session, ++ unsigned char *buf, ++ size_t len) ++{ ++ /* XXX: TODO: not implemented in client; ++ * mbedtls_ssl_conf_session_tickets_cb() callbacks only for TLS server*/ ++ ++ if (len == 0) ++ return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; ++ ++ struct tls_connection *conn = p_ticket; ++ if (conn && conn->session_ticket_cb) { ++ /* XXX: have random and secret been initialized yet? ++ * or must keys first be exported? ++ * EAP-FAST uses all args, EAP-TEAP only uses secret */ ++ struct tls_random data; ++ if (tls_connection_get_random(NULL, conn, &data) != 0) ++ return MBEDTLS_ERR_SSL_INTERNAL_ERROR; ++ int ret = ++ conn->session_ticket_cb(conn->session_ticket_cb_ctx, ++ buf, len, ++ data.client_random, ++ data.server_random, ++ conn->expkey_secret); ++ if (ret == 1) { ++ conn->resumed = 1; ++ return 0; ++ } ++ emsg(MSG_ERROR, "EAP session ticket ext not implemented"); ++ return MBEDTLS_ERR_SSL_INVALID_MAC; ++ /*(non-zero return used for mbedtls debug logging)*/ ++ } ++ ++ /* XXX: TODO always use tls_mbedtls_ssl_ticket_parse() for callback? */ ++ int rc = mbedtls_ssl_ticket_parse(&tls_ctx_global.ticket_ctx, ++ session, buf, len); ++ if (conn) ++ conn->resumed = (rc == 0); ++ return rc; ++} ++ ++#endif /* TLS_MBEDTLS_SESSION_TICKETS */ ++ ++ ++__attribute_cold__ ++int tls_global_set_params(void *tls_ctx, ++ const struct tls_connection_params *params) ++{ ++ /* XXX: why might global_set_params be called more than once? */ ++ if (tls_ctx_global.tls_conf) ++ tls_conf_deinit(tls_ctx_global.tls_conf); ++ tls_ctx_global.tls_conf = tls_conf_init(tls_ctx); ++ if (tls_ctx_global.tls_conf == NULL) ++ return -1; ++ ++ #ifdef MBEDTLS_SSL_SESSION_TICKETS ++ #ifdef MBEDTLS_SSL_TICKET_C ++ if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET)) ++ #ifdef TLS_MBEDTLS_SESSION_TICKETS ++ mbedtls_ssl_conf_session_tickets_cb(&tls_ctx_global.tls_conf->conf, ++ tls_mbedtls_ssl_ticket_write, ++ tls_mbedtls_ssl_ticket_parse, ++ NULL); ++ #else ++ mbedtls_ssl_conf_session_tickets_cb(&tls_ctx_global.tls_conf->conf, ++ mbedtls_ssl_ticket_write, ++ mbedtls_ssl_ticket_parse, ++ &tls_ctx_global.ticket_ctx); ++ #endif ++ #endif ++ #endif ++ ++ os_free(tls_ctx_global.ocsp_stapling_response); ++ tls_ctx_global.ocsp_stapling_response = NULL; ++ if (params->ocsp_stapling_response) ++ tls_ctx_global.ocsp_stapling_response = ++ os_strdup(params->ocsp_stapling_response); ++ ++ os_free(tls_ctx_global.ca_cert_file); ++ tls_ctx_global.ca_cert_file = NULL; ++ if (params->ca_cert) ++ tls_ctx_global.ca_cert_file = os_strdup(params->ca_cert); ++ return tls_mbedtls_set_params(tls_ctx_global.tls_conf, params); ++} ++ ++ ++int tls_global_set_verify(void *tls_ctx, int check_crl, int strict) ++{ ++ tls_ctx_global.tls_conf->check_crl = check_crl; ++ tls_ctx_global.tls_conf->check_crl_strict = strict; /*(time checks)*/ ++ return 0; ++} ++ ++ ++int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, ++ int verify_peer, unsigned int flags, ++ const u8 *session_ctx, size_t session_ctx_len) ++{ ++ /*(EAP server-side calls this from eap_server_tls_ssl_init())*/ ++ if (conn == NULL) ++ return -1; ++ ++ conn->tls_conf->flags |= flags;/* TODO: reprocess flags, if necessary */ ++ ++ int authmode; ++ switch (verify_peer) { ++ case 2: authmode = MBEDTLS_SSL_VERIFY_OPTIONAL; break;/*(eap_teap_init())*/ ++ case 1: authmode = MBEDTLS_SSL_VERIFY_REQUIRED; break; ++ default: authmode = MBEDTLS_SSL_VERIFY_NONE; break; ++ } ++ mbedtls_ssl_set_hs_authmode(&conn->ssl, authmode); ++ ++ if ((conn->verify_peer = (authmode != MBEDTLS_SSL_VERIFY_NONE))) ++ mbedtls_ssl_set_verify(&conn->ssl, tls_mbedtls_verify_cb, conn); ++ else ++ mbedtls_ssl_set_verify(&conn->ssl, NULL, NULL); ++ ++ return 0; ++} ++ ++ ++#if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++static void tls_connection_export_keys_cb( ++ void *p_expkey, mbedtls_ssl_key_export_type secret_type, ++ const unsigned char *secret, size_t secret_len, ++ const unsigned char client_random[MBEDTLS_EXPKEY_RAND_LEN], ++ const unsigned char server_random[MBEDTLS_EXPKEY_RAND_LEN], ++ mbedtls_tls_prf_types tls_prf_type) ++{ ++ struct tls_connection *conn = p_expkey; ++ conn->tls_prf_type = tls_prf_type; ++ if (!tls_prf_type) ++ return; ++ if (secret_len > sizeof(conn->expkey_secret)) { ++ emsg(MSG_ERROR, "tls_connection_export_keys_cb secret too long"); ++ conn->tls_prf_type = MBEDTLS_SSL_TLS_PRF_NONE; /* 0 */ ++ return; ++ } ++ conn->expkey_secret_len = secret_len; ++ os_memcpy(conn->expkey_secret, secret, secret_len); ++ os_memcpy(conn->expkey_randbytes, ++ client_random, MBEDTLS_EXPKEY_RAND_LEN); ++ os_memcpy(conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN, ++ server_random, MBEDTLS_EXPKEY_RAND_LEN); ++} ++#elif MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++static int tls_connection_export_keys_cb( ++ void *p_expkey, ++ const unsigned char *ms, ++ const unsigned char *kb, ++ size_t maclen, ++ size_t keylen, ++ size_t ivlen, ++ const unsigned char client_random[MBEDTLS_EXPKEY_RAND_LEN], ++ const unsigned char server_random[MBEDTLS_EXPKEY_RAND_LEN], ++ mbedtls_tls_prf_types tls_prf_type ) ++{ ++ struct tls_connection *conn = p_expkey; ++ conn->tls_prf_type = tls_prf_type; ++ if (!tls_prf_type) ++ return -1; /*(return value ignored by mbedtls)*/ ++ conn->expkey_keyblock_size = maclen + keylen + ivlen; ++ conn->expkey_secret_len = MBEDTLS_EXPKEY_FIXED_SECRET_LEN; ++ os_memcpy(conn->expkey_secret, ms, MBEDTLS_EXPKEY_FIXED_SECRET_LEN); ++ os_memcpy(conn->expkey_randbytes, ++ client_random, MBEDTLS_EXPKEY_RAND_LEN); ++ os_memcpy(conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN, ++ server_random, MBEDTLS_EXPKEY_RAND_LEN); ++ return 0; ++} ++#endif ++ ++ ++int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn, ++ struct tls_random *data) ++{ ++ if (!conn || !conn->tls_prf_type) ++ return -1; ++ data->client_random = conn->expkey_randbytes; ++ data->client_random_len = MBEDTLS_EXPKEY_RAND_LEN; ++ data->server_random = conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN; ++ data->server_random_len = MBEDTLS_EXPKEY_RAND_LEN; ++ return 0; ++} ++ ++ ++int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, ++ const char *label, const u8 *context, ++ size_t context_len, u8 *out, size_t out_len) ++{ ++ /* (EAP-PEAP EAP-TLS EAP-TTLS) */ ++ #if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++ return (conn && conn->established && conn->tls_prf_type) ++ ? mbedtls_ssl_tls_prf(conn->tls_prf_type, ++ conn->expkey_secret, conn->expkey_secret_len, label, ++ conn->expkey_randbytes, ++ sizeof(conn->expkey_randbytes), out, out_len) ++ : -1; ++ #else ++ /* not implemented here for mbedtls < 2.18.0 */ ++ return -1; ++ #endif ++} ++ ++ ++#ifdef TLS_MBEDTLS_EAP_FAST ++ ++#if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++/* keyblock size info is not exposed in mbed TLS 3.0.0 */ ++/* extracted from mbedtls library/ssl_tls.c:ssl_tls12_populate_transform() */ ++#include <mbedtls/ssl_ciphersuites.h> ++#include <mbedtls/cipher.h> ++static size_t tls_mbedtls_ssl_keyblock_size (mbedtls_ssl_context *ssl) ++{ ++ #if !defined(MBEDTLS_USE_PSA_CRYPTO) /* XXX: (not extracted for PSA crypto) */ ++ #if defined(MBEDTLS_SSL_PROTO_TLS1_3) ++ if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) ++ return 0; /* (calculation not extracted) */ ++ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ ++ ++ int ciphersuite = mbedtls_ssl_get_ciphersuite_id_from_ssl(ssl); ++ const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ++ mbedtls_ssl_ciphersuite_from_id(ciphersuite); ++ if (ciphersuite_info == NULL) ++ return 0; ++ ++ const mbedtls_cipher_info_t *cipher_info = ++ mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher)); ++ if (cipher_info == NULL) ++ return 0; ++ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03010000 /* mbedtls 3.1.0 */ ++ size_t keylen = mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8; ++ mbedtls_cipher_mode_t mode = mbedtls_cipher_info_get_mode(cipher_info); ++ #else ++ size_t keylen = cipher_info->MBEDTLS_PRIVATE(key_bitlen) / 8; ++ mbedtls_cipher_mode_t mode = cipher_info->MBEDTLS_PRIVATE(mode); ++ #endif ++ #if defined(MBEDTLS_GCM_C) || \ ++ defined(MBEDTLS_CCM_C) || \ ++ defined(MBEDTLS_CHACHAPOLY_C) ++ if (mode == MBEDTLS_MODE_GCM || mode == MBEDTLS_MODE_CCM) ++ return keylen + 4; ++ else if (mode == MBEDTLS_MODE_CHACHAPOLY) ++ return keylen + 12; ++ else ++ #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */ ++ #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) ++ { ++ const mbedtls_md_info_t *md_info = ++ mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac)); ++ if (md_info == NULL) ++ return 0; ++ size_t mac_key_len = mbedtls_md_get_size(md_info); ++ size_t ivlen = mbedtls_cipher_info_get_iv_size(cipher_info); ++ return keylen + mac_key_len + ivlen; ++ } ++ #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ ++ #endif /* !MBEDTLS_USE_PSA_CRYPTO *//* (not extracted for PSA crypto) */ ++ return 0; ++} ++#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 *//* mbedtls 3.0.0 */ ++ ++ ++int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, ++ u8 *out, size_t out_len) ++{ ++ /* XXX: has export keys callback been run? */ ++ if (!conn || !conn->tls_prf_type) ++ return -1; ++ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ conn->expkey_keyblock_size = tls_mbedtls_ssl_keyblock_size(&conn->ssl); ++ if (conn->expkey_keyblock_size == 0) ++ return -1; ++ #endif ++ size_t skip = conn->expkey_keyblock_size * 2; ++ unsigned char *tmp_out = os_malloc(skip + out_len); ++ if (!tmp_out) ++ return -1; ++ ++ /* server_random and then client_random */ ++ unsigned char seed[MBEDTLS_EXPKEY_RAND_LEN*2]; ++ os_memcpy(seed, conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN, ++ MBEDTLS_EXPKEY_RAND_LEN); ++ os_memcpy(seed + MBEDTLS_EXPKEY_RAND_LEN, conn->expkey_randbytes, ++ MBEDTLS_EXPKEY_RAND_LEN); ++ ++ #if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++ int ret = mbedtls_ssl_tls_prf(conn->tls_prf_type, ++ conn->expkey_secret, conn->expkey_secret_len, ++ "key expansion", seed, sizeof(seed), ++ tmp_out, skip + out_len); ++ if (ret == 0) ++ os_memcpy(out, tmp_out + skip, out_len); ++ #else ++ int ret = -1; /*(not reached if not impl; return -1 at top of func)*/ ++ #endif ++ ++ bin_clear_free(tmp_out, skip + out_len); ++ forced_memzero(seed, sizeof(seed)); ++ return ret; ++} ++ ++#endif /* TLS_MBEDTLS_EAP_FAST */ ++ ++ ++__attribute_cold__ ++static void tls_mbedtls_suiteb_handshake_alert (struct tls_connection *conn) ++{ ++ /* tests/hwsim/test_suite_b.py test_suite_b_192_rsa_insufficient_dh */ ++ if (!(conn->tls_conf->flags & TLS_CONN_SUITEB)) ++ return; ++ if (tls_ctx_global.tls_conf) /*(is server; want issue event on client)*/ ++ return; ++ #if 0 ++ /*(info not available on client; ++ * mbed TLS library enforces dhm min bitlen in ServerKeyExchange)*/ ++ if (MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 == ++ #if MBEDTLS_VERSION_NUMBER < 0x03020000 /* mbedtls 3.2.0 */ ++ mbedtls_ssl_get_ciphersuite_id_from_ssl(&conn->ssl) ++ #else ++ mbedtls_ssl_get_ciphersuite_id( ++ mbedtls_ssl_get_ciphersuite(&conn->ssl)) ++ #endif ++ && mbedtls_mpi_size(&conn->tls_conf->conf.MBEDTLS_PRIVATE(dhm_P)) ++ < 384 /*(3072/8)*/) ++ #endif ++ { ++ struct tls_config *init_conf = &tls_ctx_global.init_conf; ++ if (init_conf->event_cb) { ++ union tls_event_data ev; ++ os_memset(&ev, 0, sizeof(ev)); ++ ev.alert.is_local = 1; ++ ev.alert.type = "fatal"; ++ /*"internal error" string for tests/hwsim/test_suiteb.py */ ++ ev.alert.description = "internal error: handshake failure"; ++ /*ev.alert.description = "insufficient security";*/ ++ init_conf->event_cb(init_conf->cb_ctx, TLS_ALERT, &ev); ++ } ++ } ++} ++ ++ ++struct wpabuf * tls_connection_handshake(void *tls_ctx, ++ struct tls_connection *conn, ++ const struct wpabuf *in_data, ++ struct wpabuf **appl_data) ++{ ++ if (appl_data) ++ *appl_data = NULL; ++ ++ if (in_data && wpabuf_len(in_data)) { ++ /*(unsure why tls_gnutls.c discards buffer contents; skip here)*/ ++ if (conn->pull_buf && 0) /* disable; appears unwise */ ++ tls_pull_buf_discard(conn, __func__); ++ if (!tls_pull_buf_append(conn, in_data)) ++ return NULL; ++ } ++ ++ if (conn->tls_conf == NULL) { ++ struct tls_connection_params params; ++ os_memset(¶ms, 0, sizeof(params)); ++ params.openssl_ciphers = ++ tls_ctx_global.init_conf.openssl_ciphers; ++ params.flags = tls_ctx_global.tls_conf->flags; ++ if (tls_connection_set_params(tls_ctx, conn, ¶ms) != 0) ++ return NULL; ++ } ++ ++ if (conn->verify_peer) /*(call here might be redundant; nbd)*/ ++ mbedtls_ssl_set_verify(&conn->ssl, tls_mbedtls_verify_cb, conn); ++ ++ #ifdef TLS_MBEDTLS_SESSION_TICKETS ++ if (conn->clienthello_session_ticket) ++ /*(starting handshake for EAP-FAST and EAP-TEAP)*/ ++ tls_mbedtls_clienthello_session_ticket_set(conn); ++ ++ /* (not thread-safe due to need to set userdata 'conn' for callback) */ ++ /* (unable to use mbedtls_ssl_set_user_data_p() with mbedtls 3.2.0+ ++ * since ticket write and parse callbacks take (mbedtls_ssl_session *) ++ * param instead of (mbedtls_ssl_context *) param) */ ++ if (conn->tls_conf->flags & TLS_CONN_DISABLE_SESSION_TICKET) ++ mbedtls_ssl_conf_session_tickets_cb(&conn->tls_conf->conf, ++ NULL, NULL, NULL); ++ else ++ mbedtls_ssl_conf_session_tickets_cb(&conn->tls_conf->conf, ++ tls_mbedtls_ssl_ticket_write, ++ tls_mbedtls_ssl_ticket_parse, ++ conn); ++ #endif ++ ++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */ ++ int ret = mbedtls_ssl_handshake(&conn->ssl); ++ #else ++ int ret = 0; ++ while (conn->ssl.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) { ++ ret = mbedtls_ssl_handshake_step(&conn->ssl); ++ if (ret != 0) ++ break; ++ } ++ #endif ++ ++ #ifdef TLS_MBEDTLS_SESSION_TICKETS ++ mbedtls_ssl_conf_session_tickets_cb(&conn->tls_conf->conf, ++ tls_mbedtls_ssl_ticket_write, ++ tls_mbedtls_ssl_ticket_parse, ++ NULL); ++ #endif ++ ++ switch (ret) { ++ case 0: ++ conn->established = 1; ++ if (conn->push_buf == NULL) ++ /* Need to return something to get final TLS ACK. */ ++ conn->push_buf = wpabuf_alloc(0); ++ ++ if (appl_data /*&& conn->pull_buf && wpabuf_len(conn->pull_buf)*/) ++ *appl_data = NULL; /* RFE: check for application data */ ++ break; ++ case MBEDTLS_ERR_SSL_WANT_WRITE: ++ case MBEDTLS_ERR_SSL_WANT_READ: ++ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS: ++ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: ++ if (tls_ctx_global.tls_conf /*(is server)*/ ++ && conn->established && conn->push_buf == NULL) ++ /* Need to return something to trigger completion of EAP-TLS. */ ++ conn->push_buf = wpabuf_alloc(0); ++ break; ++ default: ++ ++conn->failed; ++ switch (ret) { ++ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT: ++ case MBEDTLS_ERR_NET_CONN_RESET: ++ case MBEDTLS_ERR_NET_SEND_FAILED: ++ ++conn->write_alerts; ++ break; ++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */ ++ case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE: ++ #else ++ case MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE: ++ #endif ++ tls_mbedtls_suiteb_handshake_alert(conn); ++ /* fall through */ ++ case MBEDTLS_ERR_NET_RECV_FAILED: ++ case MBEDTLS_ERR_SSL_CONN_EOF: ++ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: ++ case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: ++ ++conn->read_alerts; ++ break; ++ default: ++ break; ++ } ++ ++ ilog(ret, "mbedtls_ssl_handshake"); ++ break; ++ } ++ ++ struct wpabuf *out_data = conn->push_buf; ++ conn->push_buf = NULL; ++ return out_data; ++} ++ ++ ++struct wpabuf * tls_connection_server_handshake(void *tls_ctx, ++ struct tls_connection *conn, ++ const struct wpabuf *in_data, ++ struct wpabuf **appl_data) ++{ ++ conn->is_server = 1; ++ return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); ++} ++ ++ ++struct wpabuf * tls_connection_encrypt(void *tls_ctx, ++ struct tls_connection *conn, ++ const struct wpabuf *in_data) ++{ ++ int res = mbedtls_ssl_write(&conn->ssl, ++ wpabuf_head_u8(in_data), wpabuf_len(in_data)); ++ if (res < 0) { ++ elog(res, "mbedtls_ssl_write"); ++ return NULL; ++ } ++ ++ struct wpabuf *buf = conn->push_buf; ++ conn->push_buf = NULL; ++ return buf; ++} ++ ++ ++struct wpabuf * tls_connection_decrypt(void *tls_ctx, ++ struct tls_connection *conn, ++ const struct wpabuf *in_data) ++{ ++ int res; ++ struct wpabuf *out; ++ ++ /*assert(in_data != NULL);*/ ++ if (!tls_pull_buf_append(conn, in_data)) ++ return NULL; ++ ++ #if defined(MBEDTLS_ZLIB_SUPPORT) /* removed in mbedtls 3.x */ ++ /* Add extra buffer space to handle the possibility of decrypted ++ * data being longer than input data due to TLS compression. */ ++ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); ++ #else /* TLS compression is disabled in mbedtls 3.x */ ++ out = wpabuf_alloc(wpabuf_len(in_data)); ++ #endif ++ if (out == NULL) ++ return NULL; ++ ++ res = mbedtls_ssl_read(&conn->ssl, wpabuf_mhead(out), wpabuf_size(out)); ++ if (res < 0) { ++ #if 1 /*(seems like a different error if wpabuf_len(in_data) == 0)*/ ++ if (res == MBEDTLS_ERR_SSL_WANT_READ) ++ return out; ++ #endif ++ elog(res, "mbedtls_ssl_read"); ++ wpabuf_free(out); ++ return NULL; ++ } ++ wpabuf_put(out, res); ++ ++ return out; ++} ++ ++ ++int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) ++{ ++ /* XXX: might need to detect if session resumed from TLS session ticket ++ * even if not special session ticket handling for EAP-FAST, EAP-TEAP */ ++ /* (?ssl->handshake->resume during session ticket validation?) */ ++ return conn && conn->resumed; ++} ++ ++ ++#ifdef TLS_MBEDTLS_EAP_FAST ++int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, ++ u8 *ciphers) ++{ ++ /* ciphers is list of TLS_CIPHER_* from hostap/src/crypto/tls.h */ ++ int ids[7]; ++ const int idsz = (int)sizeof(ids); ++ int nids = -1, id; ++ for ( ; *ciphers != TLS_CIPHER_NONE; ++ciphers) { ++ switch (*ciphers) { ++ case TLS_CIPHER_RC4_SHA: ++ #ifdef MBEDTLS_TLS_RSA_WITH_RC4_128_SHA ++ id = MBEDTLS_TLS_RSA_WITH_RC4_128_SHA; ++ break; ++ #else ++ continue; /*(not supported in mbedtls 3.x; ignore)*/ ++ #endif ++ case TLS_CIPHER_AES128_SHA: ++ id = MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA; ++ break; ++ case TLS_CIPHER_RSA_DHE_AES128_SHA: ++ id = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA; ++ break; ++ case TLS_CIPHER_ANON_DH_AES128_SHA: ++ continue; /*(not supported in mbedtls; ignore)*/ ++ case TLS_CIPHER_RSA_DHE_AES256_SHA: ++ id = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA; ++ break; ++ case TLS_CIPHER_AES256_SHA: ++ id = MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA; ++ break; ++ default: ++ return -1; /* should not happen */ ++ } ++ if (++nids == idsz) ++ return -1; /* should not happen */ ++ ids[nids] = id; ++ } ++ if (nids < 0) ++ return 0; /* nothing to do */ ++ if (++nids == idsz) ++ return -1; /* should not happen */ ++ ids[nids] = 0; /* terminate list */ ++ ++nids; ++ ++ return tls_mbedtls_set_ciphersuites(conn->tls_conf, ids, nids) ? 0 : -1; ++} ++#endif ++ ++ ++int tls_get_version(void *ssl_ctx, struct tls_connection *conn, ++ char *buf, size_t buflen) ++{ ++ if (conn == NULL) ++ return -1; ++ os_strlcpy(buf, mbedtls_ssl_get_version(&conn->ssl), buflen); ++ return buf[0] != 'u' ? 0 : -1; /*(-1 if "unknown")*/ ++} ++ ++ ++#ifdef TLS_MBEDTLS_EAP_TEAP ++u16 tls_connection_get_cipher_suite(struct tls_connection *conn) ++{ ++ if (conn == NULL) ++ return 0; ++ return (u16)mbedtls_ssl_get_ciphersuite_id_from_ssl(&conn->ssl); ++} ++#endif ++ ++ ++int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, ++ char *buf, size_t buflen) ++{ ++ if (conn == NULL) ++ return -1; ++ const int id = mbedtls_ssl_get_ciphersuite_id_from_ssl(&conn->ssl); ++ return tls_mbedtls_translate_ciphername(id, buf, buflen) ? 0 : -1; ++} ++ ++ ++#ifdef TLS_MBEDTLS_SESSION_TICKETS ++ ++int tls_connection_enable_workaround(void *tls_ctx, ++ struct tls_connection *conn) ++{ ++ /* (see comment in src/eap_peer/eap_fast.c:eap_fast_init()) */ ++ /* XXX: is there a relevant setting for this in mbed TLS? */ ++ /* (do we even care that much about older CBC ciphers?) */ ++ return 0; ++} ++ ++ ++int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, ++ int ext_type, const u8 *data, ++ size_t data_len) ++{ ++ /* (EAP-FAST and EAP-TEAP) */ ++ if (ext_type == MBEDTLS_TLS_EXT_SESSION_TICKET) /*(ext_type == 35)*/ ++ return tls_mbedtls_clienthello_session_ticket_prep(conn, data, ++ data_len); ++ ++ return -1; ++} ++ ++#endif /* TLS_MBEDTLS_SESSION_TICKETS */ ++ ++ ++int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) ++{ ++ return conn ? conn->failed : -1; ++} ++ ++ ++int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) ++{ ++ return conn ? conn->read_alerts : -1; ++} ++ ++ ++int tls_connection_get_write_alerts(void *tls_ctx, ++ struct tls_connection *conn) ++{ ++ return conn ? conn->write_alerts : -1; ++} ++ ++ ++#ifdef TLS_MBEDTLS_SESSION_TICKETS ++int tls_connection_set_session_ticket_cb( ++ void *tls_ctx, struct tls_connection *conn, ++ tls_session_ticket_cb cb, void *ctx) ++{ ++ if (!(conn->tls_conf->flags & TLS_CONN_DISABLE_SESSION_TICKET)) { ++ /* (EAP-FAST and EAP-TEAP) */ ++ conn->session_ticket_cb = cb; ++ conn->session_ticket_cb_ctx = ctx; ++ return 0; ++ } ++ return -1; ++} ++#endif ++ ++ ++int tls_get_library_version(char *buf, size_t buf_len) ++{ ++ #ifndef MBEDTLS_VERSION_C ++ const char * const ver = "n/a"; ++ #else ++ char ver[9]; ++ mbedtls_version_get_string(ver); ++ #endif ++ return os_snprintf(buf, buf_len, ++ "mbed TLS build=" MBEDTLS_VERSION_STRING " run=%s", ver); ++} ++ ++ ++void tls_connection_set_success_data(struct tls_connection *conn, ++ struct wpabuf *data) ++{ ++ wpabuf_free(conn->success_data); ++ conn->success_data = data; ++} ++ ++ ++void tls_connection_set_success_data_resumed(struct tls_connection *conn) ++{ ++} ++ ++ ++const struct wpabuf * ++tls_connection_get_success_data(struct tls_connection *conn) ++{ ++ return conn->success_data; ++} ++ ++ ++void tls_connection_remove_session(struct tls_connection *conn) ++{ ++} ++ ++ ++#ifdef TLS_MBEDTLS_EAP_TEAP ++int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len) ++{ ++ #if defined(MBEDTLS_SSL_RENEGOTIATION) /* XXX: renegotiation or resumption? */ ++ /* data from TLS handshake Finished message */ ++ size_t verify_len = conn->ssl.MBEDTLS_PRIVATE(verify_data_len); ++ char *verify_data = (conn->is_server ^ conn->resumed) ++ ? conn->ssl.MBEDTLS_PRIVATE(peer_verify_data) ++ : conn->ssl.MBEDTLS_PRIVATE(own_verify_data); ++ if (verify_len && verify_len <= max_len) { ++ os_memcpy(buf, verify_data, verify_len); ++ return (int)verify_len; ++ } ++ #endif ++ return -1; ++} ++#endif ++ ++ ++__attribute_noinline__ ++static void tls_mbedtls_set_peer_subject(struct tls_connection *conn, const mbedtls_x509_crt *crt) ++{ ++ if (conn->peer_subject) ++ return; ++ char buf[MBEDTLS_X509_MAX_DN_NAME_SIZE*2]; ++ int buflen = mbedtls_x509_dn_gets(buf, sizeof(buf), &crt->subject); ++ if (buflen >= 0 && (conn->peer_subject = os_malloc((size_t)buflen+1))) ++ os_memcpy(conn->peer_subject, buf, (size_t)buflen+1); ++} ++ ++ ++#ifdef TLS_MBEDTLS_EAP_TEAP ++const char * tls_connection_get_peer_subject(struct tls_connection *conn) ++{ ++ if (!conn) ++ return NULL; ++ if (!conn->peer_subject) { /*(if not set during cert verify)*/ ++ const mbedtls_x509_crt *peer_cert = ++ mbedtls_ssl_get_peer_cert(&conn->ssl); ++ if (peer_cert) ++ tls_mbedtls_set_peer_subject(conn, peer_cert); ++ } ++ return conn->peer_subject; ++} ++#endif ++ ++ ++#ifdef TLS_MBEDTLS_EAP_TEAP ++bool tls_connection_get_own_cert_used(struct tls_connection *conn) ++{ ++ /* XXX: availability of cert does not necessary mean that client ++ * received certificate request from server and then sent cert. ++ * ? step handshake in tls_connection_handshake() looking for ++ * MBEDTLS_SSL_CERTIFICATE_REQUEST ? */ ++ const struct tls_conf * const tls_conf = conn->tls_conf; ++ return (tls_conf->has_client_cert && tls_conf->has_private_key); ++} ++#endif ++ ++ ++#if defined(CONFIG_FIPS) ++#define TLS_MBEDTLS_CONFIG_FIPS ++#endif ++ ++#if defined(CONFIG_SHA256) ++#define TLS_MBEDTLS_TLS_PRF_SHA256 ++#endif ++ ++#if defined(CONFIG_SHA384) ++#define TLS_MBEDTLS_TLS_PRF_SHA384 ++#endif ++ ++ ++#ifndef TLS_MBEDTLS_CONFIG_FIPS ++#if defined(CONFIG_MODULE_TESTS) ++/* unused with CONFIG_TLS=mbedtls except in crypto_module_tests.c */ ++#if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ \ ++ && MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */ ++/* sha1-tlsprf.c */ ++#include "sha1.h" ++int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label, ++ const u8 *seed, size_t seed_len, u8 *out, size_t outlen) ++{ ++ return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_TLS1, ++ secret, secret_len, label, ++ seed, seed_len, out, outlen) ? -1 : 0; ++} ++#else ++#include "sha1-tlsprf.c" /* pull in hostap local implementation */ ++#endif ++#endif ++#endif ++ ++#ifdef TLS_MBEDTLS_TLS_PRF_SHA256 ++/* sha256-tlsprf.c */ ++#if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++#include "sha256.h" ++int tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label, ++ const u8 *seed, size_t seed_len, u8 *out, size_t outlen) ++{ ++ return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_SHA256, ++ secret, secret_len, label, ++ seed, seed_len, out, outlen) ? -1 : 0; ++} ++#else ++#include "sha256-tlsprf.c" /* pull in hostap local implementation */ ++#endif ++#endif ++ ++#ifdef TLS_MBEDTLS_TLS_PRF_SHA384 ++/* sha384-tlsprf.c */ ++#if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ ++#include "sha384.h" ++int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label, ++ const u8 *seed, size_t seed_len, u8 *out, size_t outlen) ++{ ++ return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_SHA384, ++ secret, secret_len, label, ++ seed, seed_len, out, outlen) ? -1 : 0; ++} ++#else ++#include "sha384-tlsprf.c" /* pull in hostap local implementation */ ++#endif ++#endif ++ ++ ++#if MBEDTLS_VERSION_NUMBER < 0x03020000 /* mbedtls 3.2.0 */ ++#define mbedtls_x509_crt_has_ext_type(crt, ext_type) \ ++ ((crt)->MBEDTLS_PRIVATE(ext_types) & (ext_type)) ++#endif ++ ++struct mlist { const char *p; size_t n; }; ++ ++ ++static int ++tls_mbedtls_match_altsubject(mbedtls_x509_crt *crt, const char *match) ++{ ++ /* RFE: this could be pre-parsed into structured data at config time */ ++ struct mlist list[256]; /*(much larger than expected)*/ ++ int nlist = 0; ++ if ( os_strncmp(match, "EMAIL:", 6) != 0 ++ && os_strncmp(match, "DNS:", 4) != 0 ++ && os_strncmp(match, "URI:", 4) != 0 ) { ++ wpa_printf(MSG_INFO, "MTLS: Invalid altSubjectName match '%s'", match); ++ return 0; ++ } ++ for (const char *s = match, *tok; *s; s = tok ? tok+1 : "") { ++ do { } while ((tok = os_strchr(s, ';')) ++ && os_strncmp(tok+1, "EMAIL:", 6) != 0 ++ && os_strncmp(tok+1, "DNS:", 4) != 0 ++ && os_strncmp(tok+1, "URI:", 4) != 0); ++ list[nlist].p = s; ++ list[nlist].n = tok ? (size_t)(tok - s) : os_strlen(s); ++ if (list[nlist].n && ++nlist == sizeof(list)/sizeof(*list)) { ++ wpa_printf(MSG_INFO, "MTLS: excessive altSubjectName match '%s'", ++ match); ++ break; /* truncate huge list and continue */ ++ } ++ } ++ ++ if (!mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)) ++ return 0; ++ ++ const mbedtls_x509_sequence *cur = &crt->subject_alt_names; ++ for (; cur != NULL; cur = cur->next) { ++ const unsigned char san_type = (unsigned char)cur->buf.tag ++ & MBEDTLS_ASN1_TAG_VALUE_MASK; ++ char t; ++ size_t step = 4; ++ switch (san_type) { /* "EMAIL:" or "DNS:" or "URI:" */ ++ case MBEDTLS_X509_SAN_RFC822_NAME: step = 6; t = 'E'; break; ++ case MBEDTLS_X509_SAN_DNS_NAME: t = 'D'; break; ++ case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER: t = 'U'; break; ++ default: continue; ++ } ++ ++ for (int i = 0; i < nlist; ++i) { ++ /* step over "EMAIL:" or "DNS:" or "URI:" in list[i].p */ ++ /* Note: v is not '\0'-terminated, but is a known length vlen, ++ * so okay to pass to os_strncasecmp() even though not z-string */ ++ if (cur->buf.len == list[i].n - step && t == *list[i].p ++ && 0 == os_strncasecmp((char *)cur->buf.p, ++ list[i].p+step, cur->buf.len)) { ++ return 1; /* match */ ++ } ++ } ++ } ++ return 0; /* no match */ ++} ++ ++ ++static int ++tls_mbedtls_match_suffix(const char *v, size_t vlen, ++ const struct mlist *list, int nlist, int full) ++{ ++ /* Note: v is not '\0'-terminated, but is a known length vlen, ++ * so okay to pass to os_strncasecmp() even though not z-string */ ++ for (int i = 0; i < nlist; ++i) { ++ size_t n = list[i].n; ++ if ((n == vlen || (n < vlen && v[vlen-n-1] == '.' && !full)) ++ && 0 == os_strncasecmp(v+vlen-n, list[i].p, n)) ++ return 1; /* match */ ++ } ++ return 0; /* no match */ ++} ++ ++ ++static int ++tls_mbedtls_match_suffixes(mbedtls_x509_crt *crt, const char *match, int full) ++{ ++ /* RFE: this could be pre-parsed into structured data at config time */ ++ struct mlist list[256]; /*(much larger than expected)*/ ++ int nlist = 0; ++ for (const char *s = match, *tok; *s; s = tok ? tok+1 : "") { ++ tok = os_strchr(s, ';'); ++ list[nlist].p = s; ++ list[nlist].n = tok ? (size_t)(tok - s) : os_strlen(s); ++ if (list[nlist].n && ++nlist == sizeof(list)/sizeof(*list)) { ++ wpa_printf(MSG_INFO, "MTLS: excessive suffix match '%s'", match); ++ break; /* truncate huge list and continue */ ++ } ++ } ++ ++ /* check subjectAltNames */ ++ if (mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)) { ++ const mbedtls_x509_sequence *cur = &crt->subject_alt_names; ++ for (; cur != NULL; cur = cur->next) { ++ const unsigned char san_type = (unsigned char)cur->buf.tag ++ & MBEDTLS_ASN1_TAG_VALUE_MASK; ++ if (san_type == MBEDTLS_X509_SAN_DNS_NAME ++ && tls_mbedtls_match_suffix((char *)cur->buf.p, ++ cur->buf.len, ++ list, nlist, full)) { ++ return 1; /* match */ ++ } ++ } ++ } ++ ++ /* check subject CN */ ++ const mbedtls_x509_name *name = &crt->subject; ++ for (; name != NULL; name = name->next) { ++ if (name->oid.p && MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0) ++ break; ++ } ++ if (name && tls_mbedtls_match_suffix((char *)name->val.p, name->val.len, ++ list, nlist, full)) { ++ return 1; /* match */ ++ } ++ ++ return 0; /* no match */ ++} ++ ++ ++static int ++tls_mbedtls_match_dn_field(mbedtls_x509_crt *crt, const char *match) ++{ ++ /* RFE: this could be pre-parsed into structured data at config time */ ++ struct mlistoid { const char *p; size_t n; ++ const char *oid; size_t olen; ++ int prefix; }; ++ struct mlistoid list[32]; /*(much larger than expected)*/ ++ int nlist = 0; ++ for (const char *s = match, *tok, *e; *s; s = tok ? tok+1 : "") { ++ tok = os_strchr(s, '/'); ++ list[nlist].oid = NULL; ++ list[nlist].olen = 0; ++ list[nlist].n = tok ? (size_t)(tok - s) : os_strlen(s); ++ e = memchr(s, '=', list[nlist].n); ++ if (e == NULL) { ++ if (list[nlist].n == 0) ++ continue; /* skip consecutive, repeated '/' */ ++ if (list[nlist].n == 1 && *s == '*') { ++ /* special-case "*" to match any OID and value */ ++ s = e = "=*"; ++ list[nlist].n = 2; ++ list[nlist].oid = ""; ++ } ++ else { ++ wpa_printf(MSG_INFO, ++ "MTLS: invalid check_cert_subject '%s' missing '='", ++ match); ++ return 0; ++ } ++ } ++ switch (e - s) { ++ case 1: ++ if (*s == 'C') { ++ list[nlist].oid = MBEDTLS_OID_AT_COUNTRY; ++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_COUNTRY)-1; ++ } ++ else if (*s == 'L') { ++ list[nlist].oid = MBEDTLS_OID_AT_LOCALITY; ++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_LOCALITY)-1; ++ } ++ else if (*s == 'O') { ++ list[nlist].oid = MBEDTLS_OID_AT_ORGANIZATION; ++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_ORGANIZATION)-1; ++ } ++ break; ++ case 2: ++ if (s[0] == 'C' && s[1] == 'N') { ++ list[nlist].oid = MBEDTLS_OID_AT_CN; ++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_CN)-1; ++ } ++ else if (s[0] == 'S' && s[1] == 'T') { ++ list[nlist].oid = MBEDTLS_OID_AT_STATE; ++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_STATE)-1; ++ } ++ else if (s[0] == 'O' && s[1] == 'U') { ++ list[nlist].oid = MBEDTLS_OID_AT_ORG_UNIT; ++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_ORG_UNIT)-1; ++ } ++ break; ++ case 12: ++ if (os_memcmp(s, "emailAddress", 12) == 0) { ++ list[nlist].oid = MBEDTLS_OID_PKCS9_EMAIL; ++ list[nlist].olen = sizeof(MBEDTLS_OID_PKCS9_EMAIL)-1; ++ } ++ break; ++ default: ++ break; ++ } ++ if (list[nlist].oid == NULL) { ++ wpa_printf(MSG_INFO, ++ "MTLS: Unknown field in check_cert_subject '%s'", ++ match); ++ return 0; ++ } ++ list[nlist].n -= (size_t)(++e - s); ++ list[nlist].p = e; ++ if (list[nlist].n && e[list[nlist].n-1] == '*') { ++ --list[nlist].n; ++ list[nlist].prefix = 1; ++ } ++ /*(could easily add support for suffix matches if value begins with '*', ++ * but suffix match is not currently supported by other TLS modules)*/ ++ ++ if (list[nlist].n && ++nlist == sizeof(list)/sizeof(*list)) { ++ wpa_printf(MSG_INFO, ++ "MTLS: excessive check_cert_subject match '%s'", ++ match); ++ break; /* truncate huge list and continue */ ++ } ++ } ++ ++ /* each component in match string must match cert Subject in order listed ++ * The behavior below preserves ordering but is slightly different than ++ * the grossly inefficient contortions implemented in tls_openssl.c */ ++ const mbedtls_x509_name *name = &crt->subject; ++ for (int i = 0; i < nlist; ++i) { ++ int found = 0; ++ for (; name != NULL && !found; name = name->next) { ++ if (!name->oid.p) ++ continue; ++ /* special-case "*" to match any OID and value */ ++ if (list[i].olen == 0) { ++ found = 1; ++ continue; ++ } ++ /* perform equalent of !MBEDTLS_OID_CMP() with oid ptr and len */ ++ if (list[i].olen != name->oid.len ++ || os_memcmp(list[i].oid, name->oid.p, name->oid.len) != 0) ++ continue; ++ /* Note: v is not '\0'-terminated, but is a known length vlen, ++ * so okay to pass to os_strncasecmp() even though not z-string */ ++ if ((list[i].prefix ++ ? list[i].n <= name->val.len /* prefix match */ ++ : list[i].n == name->val.len) /* full match */ ++ && 0 == os_strncasecmp((char *)name->val.p, ++ list[i].p, list[i].n)) { ++ found = 1; ++ continue; ++ } ++ } ++ if (!found) ++ return 0; /* no match */ ++ } ++ return 1; /* match */ ++} ++ ++ ++__attribute_cold__ ++static void ++tls_mbedtls_verify_fail_event (mbedtls_x509_crt *crt, int depth, ++ const char *errmsg, enum tls_fail_reason reason) ++{ ++ struct tls_config *init_conf = &tls_ctx_global.init_conf; ++ if (init_conf->event_cb == NULL) ++ return; ++ ++ struct wpabuf *certbuf = wpabuf_alloc_copy(crt->raw.p, crt->raw.len); ++ char subject[MBEDTLS_X509_MAX_DN_NAME_SIZE*2]; ++ if (mbedtls_x509_dn_gets(subject, sizeof(subject), &crt->subject) < 0) ++ subject[0] = '\0'; ++ union tls_event_data ev; ++ os_memset(&ev, 0, sizeof(ev)); ++ ev.cert_fail.reason = reason; ++ ev.cert_fail.depth = depth; ++ ev.cert_fail.subject = subject; ++ ev.cert_fail.reason_txt = errmsg; ++ ev.cert_fail.cert = certbuf; ++ ++ init_conf->event_cb(init_conf->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); ++ ++ wpabuf_free(certbuf); ++} ++ ++ ++__attribute_noinline__ ++static void ++tls_mbedtls_verify_cert_event (struct tls_connection *conn, ++ mbedtls_x509_crt *crt, int depth) ++{ ++ struct tls_config *init_conf = &tls_ctx_global.init_conf; ++ if (init_conf->event_cb == NULL) ++ return; ++ ++ struct wpabuf *certbuf = NULL; ++ union tls_event_data ev; ++ os_memset(&ev, 0, sizeof(ev)); ++ ++ #ifdef MBEDTLS_SHA256_C ++ u8 hash[SHA256_DIGEST_LENGTH]; ++ const u8 *addr[] = { (u8 *)crt->raw.p }; ++ if (sha256_vector(1, addr, &crt->raw.len, hash) == 0) { ++ ev.peer_cert.hash = hash; ++ ev.peer_cert.hash_len = sizeof(hash); ++ } ++ #endif ++ ev.peer_cert.depth = depth; ++ char subject[MBEDTLS_X509_MAX_DN_NAME_SIZE*2]; ++ if (depth == 0) ++ ev.peer_cert.subject = conn->peer_subject; ++ if (ev.peer_cert.subject == NULL) { ++ ev.peer_cert.subject = subject; ++ if (mbedtls_x509_dn_gets(subject, sizeof(subject), &crt->subject) < 0) ++ subject[0] = '\0'; ++ } ++ ++ char serial_num[128+1]; ++ ev.peer_cert.serial_num = ++ tls_mbedtls_peer_serial_num(crt, serial_num, sizeof(serial_num)); ++ ++ const mbedtls_x509_sequence *cur; ++ ++ cur = NULL; ++ if (mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)) ++ cur = &crt->subject_alt_names; ++ for (; cur != NULL; cur = cur->next) { ++ const unsigned char san_type = (unsigned char)cur->buf.tag ++ & MBEDTLS_ASN1_TAG_VALUE_MASK; ++ size_t prelen = 4; ++ const char *pre; ++ switch (san_type) { ++ case MBEDTLS_X509_SAN_RFC822_NAME: prelen = 6; pre = "EMAIL:";break; ++ case MBEDTLS_X509_SAN_DNS_NAME: pre = "DNS:"; break; ++ case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER: pre = "URI:"; break; ++ default: continue; ++ } ++ ++ char *pos = os_malloc(prelen + cur->buf.len + 1); ++ if (pos == NULL) ++ break; ++ ev.peer_cert.altsubject[ev.peer_cert.num_altsubject] = pos; ++ os_memcpy(pos, pre, prelen); ++ /* data should be properly backslash-escaped if needed, ++ * so code below does not re-escape, but does replace CTLs */ ++ /*os_memcpy(pos+prelen, cur->buf.p, cur->buf.len);*/ ++ /*pos[prelen+cur->buf.len] = '\0';*/ ++ pos += prelen; ++ for (size_t i = 0; i < cur->buf.len; ++i) { ++ unsigned char c = cur->buf.p[i]; ++ *pos++ = (c >= 32 && c != 127) ? c : '?'; ++ } ++ *pos = '\0'; ++ ++ if (++ev.peer_cert.num_altsubject == TLS_MAX_ALT_SUBJECT) ++ break; ++ } ++ ++ cur = NULL; ++ if (mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_CERTIFICATE_POLICIES)) ++ cur = &crt->certificate_policies; ++ for (; cur != NULL; cur = cur->next) { ++ if (cur->buf.len != 11) /* len of OID_TOD_STRICT or OID_TOD_TOFU */ ++ continue; ++ /* TOD-STRICT "1.3.6.1.4.1.40808.1.3.1" */ ++ /* TOD-TOFU "1.3.6.1.4.1.40808.1.3.2" */ ++ #define OID_TOD_STRICT "\x2b\x06\x01\x04\x01\x82\xbe\x68\x01\x03\x01" ++ #define OID_TOD_TOFU "\x2b\x06\x01\x04\x01\x82\xbe\x68\x01\x03\x02" ++ if (os_memcmp(cur->buf.p, ++ OID_TOD_STRICT, sizeof(OID_TOD_STRICT)-1) == 0) { ++ ev.peer_cert.tod = 1; /* TOD-STRICT */ ++ break; ++ } ++ if (os_memcmp(cur->buf.p, ++ OID_TOD_TOFU, sizeof(OID_TOD_TOFU)-1) == 0) { ++ ev.peer_cert.tod = 2; /* TOD-TOFU */ ++ break; ++ } ++ } ++ ++ struct tls_conf *tls_conf = conn->tls_conf; ++ if (tls_conf->ca_cert_probe || (tls_conf->flags & TLS_CONN_EXT_CERT_CHECK) ++ || init_conf->cert_in_cb) { ++ certbuf = wpabuf_alloc_copy(crt->raw.p, crt->raw.len); ++ ev.peer_cert.cert = certbuf; ++ } ++ ++ init_conf->event_cb(init_conf->cb_ctx, TLS_PEER_CERTIFICATE, &ev); ++ ++ wpabuf_free(certbuf); ++ char **altsubject; ++ *(const char ***)&altsubject = ev.peer_cert.altsubject; ++ for (size_t i = 0; i < ev.peer_cert.num_altsubject; ++i) ++ os_free(altsubject[i]); ++} ++ ++ ++static int ++tls_mbedtls_verify_cb (void *arg, mbedtls_x509_crt *crt, int depth, uint32_t *flags) ++{ ++ /* XXX: N.B. verify code not carefully tested besides hwsim tests ++ * ++ * RFE: mbedtls_x509_crt_verify_info() and enhance log trace messages ++ * RFE: review and add support for additional TLS_CONN_* flags ++ * not handling OCSP (not available in mbedtls) ++ * ... */ ++ ++ struct tls_connection *conn = (struct tls_connection *)arg; ++ struct tls_conf *tls_conf = conn->tls_conf; ++ uint32_t flags_in = *flags; ++ ++ if (depth > 8) { /*(depth 8 picked as arbitrary limit)*/ ++ emsg(MSG_WARNING, "client cert chain too long"); ++ *flags |= MBEDTLS_X509_BADCERT_OTHER; /* cert chain too long */ ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "client cert chain too long", ++ TLS_FAIL_BAD_CERTIFICATE); ++ } ++ else if (tls_conf->verify_depth0_only) { ++ if (depth > 0) ++ *flags = 0; ++ else { ++ #ifdef MBEDTLS_SHA256_C ++ u8 hash[SHA256_DIGEST_LENGTH]; ++ const u8 *addr[] = { (u8 *)crt->raw.p }; ++ if (sha256_vector(1, addr, &crt->raw.len, hash) < 0 ++ || os_memcmp(tls_conf->ca_cert_hash, hash, sizeof(hash)) != 0) { ++ *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "cert hash mismatch", ++ TLS_FAIL_UNTRUSTED); ++ } ++ else /* hash matches; ignore other issues *except* if revoked)*/ ++ *flags &= MBEDTLS_X509_BADCERT_REVOKED; ++ #endif ++ } ++ } ++ else if (depth == 0) { ++ if (!conn->peer_subject) ++ tls_mbedtls_set_peer_subject(conn, crt); ++ /*(use same labels to tls_mbedtls_verify_fail_event() as used in ++ * other TLS modules so that hwsim tests find exact string match)*/ ++ if (!conn->peer_subject) { /* error copying subject string */ ++ *flags |= MBEDTLS_X509_BADCERT_OTHER; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "internal error", ++ TLS_FAIL_UNSPECIFIED); ++ } ++ /*(use os_strstr() for subject match as is done in tls_mbedtls.c ++ * to follow the same behavior, even though a suffix match would ++ * make more sense. Also, note that strstr match does not ++ * normalize whitespace (between components) for comparison)*/ ++ else if (tls_conf->subject_match ++ && os_strstr(conn->peer_subject, ++ tls_conf->subject_match) == NULL) { ++ wpa_printf(MSG_WARNING, ++ "MTLS: Subject '%s' did not match with '%s'", ++ conn->peer_subject, tls_conf->subject_match); ++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "Subject mismatch", ++ TLS_FAIL_SUBJECT_MISMATCH); ++ } ++ if (tls_conf->altsubject_match ++ && !tls_mbedtls_match_altsubject(crt, tls_conf->altsubject_match)) { ++ wpa_printf(MSG_WARNING, ++ "MTLS: altSubjectName match '%s' not found", ++ tls_conf->altsubject_match); ++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "AltSubject mismatch", ++ TLS_FAIL_ALTSUBJECT_MISMATCH); ++ } ++ if (tls_conf->suffix_match ++ && !tls_mbedtls_match_suffixes(crt, tls_conf->suffix_match, 0)) { ++ wpa_printf(MSG_WARNING, ++ "MTLS: Domain suffix match '%s' not found", ++ tls_conf->suffix_match); ++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "Domain suffix mismatch", ++ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH); ++ } ++ if (tls_conf->domain_match ++ && !tls_mbedtls_match_suffixes(crt, tls_conf->domain_match, 1)) { ++ wpa_printf(MSG_WARNING, ++ "MTLS: Domain match '%s' not found", ++ tls_conf->domain_match); ++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "Domain mismatch", ++ TLS_FAIL_DOMAIN_MISMATCH); ++ } ++ if (tls_conf->check_cert_subject ++ && !tls_mbedtls_match_dn_field(crt, tls_conf->check_cert_subject)) { ++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "Distinguished Name", ++ TLS_FAIL_DN_MISMATCH); ++ } ++ if (tls_conf->flags & TLS_CONN_SUITEB) { ++ /* check RSA modulus size (public key bitlen) */ ++ const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(&crt->pk); ++ if ((pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS) ++ && mbedtls_pk_get_bitlen(&crt->pk) < 3072) { ++ /* hwsim suite_b RSA tests expect 3072 ++ * suite_b_192_rsa_ecdhe_radius_rsa2048_client ++ * suite_b_192_rsa_dhe_radius_rsa2048_client */ ++ *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "Insufficient RSA modulus size", ++ TLS_FAIL_INSUFFICIENT_KEY_LEN); ++ } ++ } ++ if (tls_conf->check_crl && tls_conf->crl == NULL) { ++ /* see tests/hwsim test_ap_eap.py ap_wpa2_eap_tls_check_crl */ ++ emsg(MSG_WARNING, "check_crl set but no CRL loaded; reject all?"); ++ *flags |= MBEDTLS_X509_BADCERT_OTHER; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "check_crl set but no CRL loaded; " ++ "reject all?", ++ TLS_FAIL_BAD_CERTIFICATE); ++ } ++ } ++ else { ++ if (tls_conf->check_crl != 2) /* 2 == verify CRLs for all certs */ ++ *flags &= ~MBEDTLS_X509_BADCERT_REVOKED; ++ } ++ ++ if (!tls_conf->check_crl_strict) { ++ *flags &= ~MBEDTLS_X509_BADCRL_EXPIRED; ++ *flags &= ~MBEDTLS_X509_BADCRL_FUTURE; ++ } ++ ++ if (tls_conf->flags & TLS_CONN_DISABLE_TIME_CHECKS) { ++ *flags &= ~MBEDTLS_X509_BADCERT_EXPIRED; ++ *flags &= ~MBEDTLS_X509_BADCERT_FUTURE; ++ } ++ ++ tls_mbedtls_verify_cert_event(conn, crt, depth); ++ ++ if (*flags) { ++ if (*flags & (MBEDTLS_X509_BADCERT_NOT_TRUSTED ++ |MBEDTLS_X509_BADCERT_CN_MISMATCH ++ |MBEDTLS_X509_BADCERT_REVOKED)) { ++ emsg(MSG_WARNING, "client cert not trusted"); ++ } ++ /* report event if flags set but no additional flags set above */ ++ /* (could translate flags to more detailed TLS_FAIL_* if needed) */ ++ if (!(*flags & ~flags_in)) { ++ enum tls_fail_reason reason = TLS_FAIL_UNSPECIFIED; ++ const char *errmsg = "cert verify fail unspecified"; ++ if (*flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) { ++ reason = TLS_FAIL_UNTRUSTED; ++ errmsg = "certificate not trusted"; ++ } ++ if (*flags & MBEDTLS_X509_BADCERT_REVOKED) { ++ reason = TLS_FAIL_REVOKED; ++ errmsg = "certificate has been revoked"; ++ } ++ if (*flags & MBEDTLS_X509_BADCERT_FUTURE) { ++ reason = TLS_FAIL_NOT_YET_VALID; ++ errmsg = "certificate not yet valid"; ++ } ++ if (*flags & MBEDTLS_X509_BADCERT_EXPIRED) { ++ reason = TLS_FAIL_EXPIRED; ++ errmsg = "certificate has expired"; ++ } ++ if (*flags & MBEDTLS_X509_BADCERT_BAD_MD) { ++ reason = TLS_FAIL_BAD_CERTIFICATE; ++ errmsg = "certificate uses insecure algorithm"; ++ } ++ tls_mbedtls_verify_fail_event(crt, depth, errmsg, reason); ++ } ++ #if 0 ++ /* ??? send (again) cert events for all certs in chain ??? ++ * (should already have been called for greater depths) */ ++ /* tls_openssl.c:tls_verify_cb() sends cert events for all certs ++ * in chain if certificate validation fails, but sends all events ++ * with depth set to 0 (might be a bug) */ ++ if (depth > 0) { ++ int pdepth = depth + 1; ++ for (mbedtls_x509_crt *pcrt; (pcrt = crt->next); ++pdepth) { ++ tls_mbedtls_verify_cert_event(conn, pcrt, pdepth); ++ } ++ } ++ #endif ++ /*(do not preserve subject if verification failed but was optional)*/ ++ if (depth == 0 && conn->peer_subject) { ++ os_free(conn->peer_subject); ++ conn->peer_subject = NULL; ++ } ++ } ++ else if (depth == 0) { ++ struct tls_config *init_conf = &tls_ctx_global.init_conf; ++ if (tls_conf->ca_cert_probe) { ++ /* reject server certificate on probe-only run */ ++ *flags |= MBEDTLS_X509_BADCERT_OTHER; ++ tls_mbedtls_verify_fail_event(crt, depth, ++ "server chain probe", ++ TLS_FAIL_SERVER_CHAIN_PROBE); ++ } ++ else if (init_conf->event_cb) { ++ /* ??? send event as soon as depth == 0 is verified ??? ++ * What about rest of chain? ++ * Follows tls_mbedtls.c behavior: */ ++ init_conf->event_cb(init_conf->cb_ctx, ++ TLS_CERT_CHAIN_SUCCESS, NULL); ++ } ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/tests/build/build-wpa_supplicant-mbedtls.config +@@ -0,0 +1,24 @@ ++CONFIG_TLS=mbedtls ++ ++CONFIG_WPS=y ++CONFIG_EAP_TLS=y ++CONFIG_EAP_MSCHAPV2=y ++ ++CONFIG_EAP_PSK=y ++CONFIG_EAP_GPSK=y ++CONFIG_EAP_AKA=y ++CONFIG_EAP_SIM=y ++CONFIG_EAP_SAKE=y ++CONFIG_EAP_PAX=y ++CONFIG_EAP_FAST=y ++CONFIG_EAP_IKEV2=y ++ ++CONFIG_SAE=y ++CONFIG_FILS=y ++CONFIG_FILS_SK_PFS=y ++CONFIG_OWE=y ++CONFIG_DPP=y ++CONFIG_SUITEB=y ++CONFIG_SUITEB192=y ++ ++CFLAGS += -Werror +--- a/tests/hwsim/example-hostapd.config ++++ b/tests/hwsim/example-hostapd.config +@@ -4,6 +4,7 @@ CONFIG_DRIVER_NONE=y + CONFIG_DRIVER_NL80211=y + CONFIG_RSN_PREAUTH=y + ++#CONFIG_TLS=mbedtls + #CONFIG_TLS=internal + #CONFIG_INTERNAL_LIBTOMMATH=y + #CONFIG_INTERNAL_LIBTOMMATH_FAST=y +@@ -39,6 +40,9 @@ endif + ifeq ($(CONFIG_TLS), wolfssl) + CONFIG_EAP_PWD=y + endif ++ifeq ($(CONFIG_TLS), mbedtls) ++CONFIG_EAP_PWD=y ++endif + CONFIG_EAP_EKE=y + CONFIG_PKCS12=y + CONFIG_RADIUS_SERVER=y +--- a/tests/hwsim/example-wpa_supplicant.config ++++ b/tests/hwsim/example-wpa_supplicant.config +@@ -2,6 +2,7 @@ + + CONFIG_TLS=openssl + #CONFIG_TLS=wolfssl ++#CONFIG_TLS=mbedtls + #CONFIG_TLS=internal + #CONFIG_INTERNAL_LIBTOMMATH=y + #CONFIG_INTERNAL_LIBTOMMATH_FAST=y +@@ -41,6 +42,9 @@ endif + ifeq ($(CONFIG_TLS), wolfssl) + CONFIG_EAP_PWD=y + endif ++ifeq ($(CONFIG_TLS), mbedtls) ++CONFIG_EAP_PWD=y ++endif + + CONFIG_USIM_SIMULATOR=y + CONFIG_SIM_SIMULATOR=y +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -1163,6 +1163,29 @@ endif + CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" + endif + ++ifeq ($(CONFIG_TLS), mbedtls) ++ifndef CONFIG_CRYPTO ++CONFIG_CRYPTO=mbedtls ++endif ++ifdef TLS_FUNCS ++OBJS += ../src/crypto/tls_mbedtls.o ++LIBS += -lmbedtls -lmbedx509 ++endif ++OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o ++OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o ++OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o ++ifdef NEED_FIPS186_2_PRF ++OBJS += ../src/crypto/fips_prf_internal.o ++SHA1OBJS += ../src/crypto/sha1-internal.o ++endif ++ifeq ($(CONFIG_CRYPTO), mbedtls) ++LIBS += -lmbedcrypto ++LIBS_p += -lmbedcrypto ++# XXX: create a config option? ++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ++endif ++endif ++ + ifeq ($(CONFIG_TLS), gnutls) + ifndef CONFIG_CRYPTO + # default to libgcrypt +@@ -1355,9 +1378,11 @@ endif + + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + NEED_INTERNAL_AES_WRAP=y + endif + endif ++endif + ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP + # Seems to be needed at least with BoringSSL + NEED_INTERNAL_AES_WRAP=y +@@ -1371,9 +1396,11 @@ endif + + ifdef NEED_INTERNAL_AES_WRAP + ifneq ($(CONFIG_TLS), linux) ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-unwrap.o + endif + endif ++endif + ifdef NEED_AES_EAX + AESOBJS += ../src/crypto/aes-eax.o + NEED_AES_CTR=y +@@ -1383,35 +1410,45 @@ AESOBJS += ../src/crypto/aes-siv.o + NEED_AES_CTR=y + endif + ifdef NEED_AES_CTR ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-ctr.o + endif ++endif + ifdef NEED_AES_ENCBLOCK ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-encblock.o + endif ++endif + NEED_AES_ENC=y + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-omac1.o + endif + endif + endif ++endif + ifdef NEED_AES_WRAP + NEED_AES_ENC=y + ifdef NEED_INTERNAL_AES_WRAP ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-wrap.o + endif + endif ++endif + ifdef NEED_AES_CBC + NEED_AES_ENC=y + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + AESOBJS += ../src/crypto/aes-cbc.o + endif + endif + endif + endif ++endif + ifdef NEED_AES_ENC + ifdef CONFIG_INTERNAL_AES + AESOBJS += ../src/crypto/aes-internal-enc.o +@@ -1426,12 +1463,16 @@ ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1.o + endif + endif + endif + endif ++endif ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-prf.o ++endif + ifdef CONFIG_INTERNAL_SHA1 + SHA1OBJS += ../src/crypto/sha1-internal.o + ifdef NEED_FIPS186_2_PRF +@@ -1443,29 +1484,37 @@ CFLAGS += -DCONFIG_NO_PBKDF2 + else + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-pbkdf2.o + endif + endif + endif ++endif + ifdef NEED_T_PRF ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-tprf.o + endif ++endif + ifdef NEED_TLS_PRF ++ifneq ($(CONFIG_TLS), mbedtls) + SHA1OBJS += ../src/crypto/sha1-tlsprf.o + endif + endif ++endif + + ifndef CONFIG_FIPS + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + MD5OBJS += ../src/crypto/md5.o + endif + endif + endif + endif + endif ++endif + ifdef NEED_MD5 + ifdef CONFIG_INTERNAL_MD5 + MD5OBJS += ../src/crypto/md5-internal.o +@@ -1520,12 +1569,17 @@ ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + SHA256OBJS += ../src/crypto/sha256.o + endif + endif + endif + endif ++endif ++ ++ifneq ($(CONFIG_TLS), mbedtls) + SHA256OBJS += ../src/crypto/sha256-prf.o ++endif + ifdef CONFIG_INTERNAL_SHA256 + SHA256OBJS += ../src/crypto/sha256-internal.o + endif +@@ -1538,50 +1592,68 @@ CFLAGS += -DCONFIG_INTERNAL_SHA512 + SHA256OBJS += ../src/crypto/sha512-internal.o + endif + ifdef NEED_TLS_PRF_SHA256 ++ifneq ($(CONFIG_TLS), mbedtls) + SHA256OBJS += ../src/crypto/sha256-tlsprf.o + endif ++endif + ifdef NEED_TLS_PRF_SHA384 ++ifneq ($(CONFIG_TLS), mbedtls) + SHA256OBJS += ../src/crypto/sha384-tlsprf.o + endif ++endif + ifdef NEED_HMAC_SHA256_KDF + CFLAGS += -DCONFIG_HMAC_SHA256_KDF ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha256-kdf.o + endif ++endif + ifdef NEED_HMAC_SHA384_KDF + CFLAGS += -DCONFIG_HMAC_SHA384_KDF ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384-kdf.o + endif ++endif + ifdef NEED_HMAC_SHA512_KDF + CFLAGS += -DCONFIG_HMAC_SHA512_KDF ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha512-kdf.o + endif ++endif + OBJS += $(SHA256OBJS) + ifdef NEED_SHA384 + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384.o + endif + endif + endif + endif ++endif + CFLAGS += -DCONFIG_SHA384 ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha384-prf.o + endif ++endif + ifdef NEED_SHA512 + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), linux) + ifneq ($(CONFIG_TLS), gnutls) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha512.o + endif + endif + endif + endif ++endif + CFLAGS += -DCONFIG_SHA512 ++ifneq ($(CONFIG_TLS), mbedtls) + OBJS += ../src/crypto/sha512-prf.o + endif ++endif + + ifdef NEED_ASN1 + OBJS += ../src/tls/asn1.o +@@ -1756,10 +1828,12 @@ ifdef CONFIG_FIPS + CFLAGS += -DCONFIG_FIPS + ifneq ($(CONFIG_TLS), openssl) + ifneq ($(CONFIG_TLS), wolfssl) ++ifneq ($(CONFIG_TLS), mbedtls) + $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl) + endif + endif + endif ++endif + + OBJS += $(SHA1OBJS) $(DESOBJS) + +--- a/wpa_supplicant/defconfig ++++ b/wpa_supplicant/defconfig +@@ -10,8 +10,8 @@ + # to override previous values of the variables. + + +-# Uncomment following two lines and fix the paths if you have installed OpenSSL +-# or GnuTLS in non-default location ++# Uncomment following two lines and fix the paths if you have installed TLS ++# libraries in a non-default location + #CFLAGS += -I/usr/local/openssl/include + #LIBS += -L/usr/local/openssl/lib + +@@ -20,6 +20,7 @@ + # used to fix build issues on such systems (krb5.h not found). + #CFLAGS += -I/usr/include/kerberos + ++ + # Driver interface for generic Linux wireless extensions + # Note: WEXT is deprecated in the current Linux kernel version and no new + # functionality is added to it. nl80211-based interface is the new +@@ -326,6 +327,7 @@ CONFIG_BACKEND=file + # openssl = OpenSSL (default) + # gnutls = GnuTLS + # internal = Internal TLSv1 implementation (experimental) ++# mbedtls = mbed TLS + # linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) + # none = Empty template + #CONFIG_TLS=openssl diff --git a/package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch b/package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch new file mode 100644 index 00000000000..a48725264fd --- /dev/null +++ b/package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch @@ -0,0 +1,114 @@ +From c8dba4bd750269bcc80fed3d546e2077cb4cdf0e Mon Sep 17 00:00:00 2001 +From: Glenn Strauss <gstrauss@gluelogic.com> +Date: Tue, 19 Jul 2022 20:02:21 -0400 +Subject: [PATCH 2/7] mbedtls: fips186_2_prf() + +Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> +--- + hostapd/Makefile | 4 --- + src/crypto/crypto_mbedtls.c | 60 +++++++++++++++++++++++++++++++++++++ + wpa_supplicant/Makefile | 4 --- + 3 files changed, 60 insertions(+), 8 deletions(-) + +--- a/hostapd/Makefile ++++ b/hostapd/Makefile +@@ -759,10 +759,6 @@ endif + OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o + HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o + SOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +-ifdef NEED_FIPS186_2_PRF +-OBJS += ../src/crypto/fips_prf_internal.o +-SHA1OBJS += ../src/crypto/sha1-internal.o +-endif + ifeq ($(CONFIG_CRYPTO), mbedtls) + ifdef CONFIG_DPP + LIBS += -lmbedx509 +--- a/src/crypto/crypto_mbedtls.c ++++ b/src/crypto/crypto_mbedtls.c +@@ -132,6 +132,12 @@ + #define CRYPTO_MBEDTLS_HMAC_KDF_SHA512 + #endif + ++#if defined(EAP_SIM) || defined(EAP_SIM_DYNAMIC) || defined(EAP_SERVER_SIM) \ ++ || defined(EAP_AKA) || defined(EAP_AKA_DYNAMIC) || defined(EAP_SERVER_AKA) ++/* EAP_SIM=y EAP_AKA=y */ ++#define CRYPTO_MBEDTLS_FIPS186_2_PRF ++#endif ++ + #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) \ + || defined(EAP_TEAP) || defined(EAP_TEAP_DYNAMIC) || defined(EAP_SERVER_FAST) + #define CRYPTO_MBEDTLS_SHA1_T_PRF +@@ -813,6 +819,60 @@ int sha1_t_prf(const u8 *key, size_t key + + #endif /* CRYPTO_MBEDTLS_SHA1_T_PRF */ + ++#ifdef CRYPTO_MBEDTLS_FIPS186_2_PRF ++ ++/* fips_prf_internal.c sha1-internal.c */ ++ ++/* used only by src/eap_common/eap_sim_common.c:eap_sim_prf() ++ * for eap_sim_derive_keys() and eap_sim_derive_keys_reauth() ++ * where xlen is 160 */ ++ ++int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) ++{ ++ /* FIPS 186-2 + change notice 1 */ ++ ++ mbedtls_sha1_context ctx; ++ u8 * const xkey = ctx.MBEDTLS_PRIVATE(buffer); ++ u32 * const xstate = ctx.MBEDTLS_PRIVATE(state); ++ const u32 xstate_init[] = ++ { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; ++ ++ mbedtls_sha1_init(&ctx); ++ os_memcpy(xkey, seed, seed_len < 64 ? seed_len : 64); ++ ++ /* note: does not fill extra bytes if (xlen % 20) (SHA1_MAC_LEN) */ ++ for (; xlen >= 20; xlen -= 20) { ++ /* XSEED_j = 0 */ ++ /* XVAL = (XKEY + XSEED_j) mod 2^b */ ++ ++ /* w_i = G(t, XVAL) */ ++ os_memcpy(xstate, xstate_init, sizeof(xstate_init)); ++ mbedtls_internal_sha1_process(&ctx, xkey); ++ ++ #if __BYTE_ORDER == __LITTLE_ENDIAN ++ xstate[0] = host_to_be32(xstate[0]); ++ xstate[1] = host_to_be32(xstate[1]); ++ xstate[2] = host_to_be32(xstate[2]); ++ xstate[3] = host_to_be32(xstate[3]); ++ xstate[4] = host_to_be32(xstate[4]); ++ #endif ++ os_memcpy(x, xstate, 20); ++ if (xlen == 20) /*(done; skip prep for next loop)*/ ++ break; ++ ++ /* XKEY = (1 + XKEY + w_i) mod 2^b */ ++ for (u32 carry = 1, k = 20; k-- > 0; carry >>= 8) ++ xkey[k] = (carry += xkey[k] + x[k]) & 0xff; ++ x += 20; ++ /* x_j = w_0|w_1 (each pair of iterations through loop)*/ ++ } ++ ++ mbedtls_sha1_free(&ctx); ++ return 0; ++} ++ ++#endif /* CRYPTO_MBEDTLS_FIPS186_2_PRF */ ++ + #endif /* MBEDTLS_SHA1_C */ + + +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -1174,10 +1174,6 @@ endif + OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o + OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o + OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +-ifdef NEED_FIPS186_2_PRF +-OBJS += ../src/crypto/fips_prf_internal.o +-SHA1OBJS += ../src/crypto/sha1-internal.o +-endif + ifeq ($(CONFIG_CRYPTO), mbedtls) + LIBS += -lmbedcrypto + LIBS_p += -lmbedcrypto diff --git a/package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch b/package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch new file mode 100644 index 00000000000..ae7620b90c1 --- /dev/null +++ b/package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch @@ -0,0 +1,421 @@ +From 31bd19e0e0254b910cccfd3ddc6a6a9222bbcfc0 Mon Sep 17 00:00:00 2001 +From: Glenn Strauss <gstrauss@gluelogic.com> +Date: Sun, 9 Oct 2022 05:12:17 -0400 +Subject: [PATCH 3/7] mbedtls: annotate with TEST_FAIL() for hwsim tests + +Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> +--- + src/crypto/crypto_mbedtls.c | 124 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 124 insertions(+) + +--- a/src/crypto/crypto_mbedtls.c ++++ b/src/crypto/crypto_mbedtls.c +@@ -280,6 +280,9 @@ __attribute_noinline__ + static int md_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac, mbedtls_md_type_t md_type) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0) != 0){ +@@ -343,6 +346,9 @@ __attribute_noinline__ + static int sha384_512_vector(size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac, int is384) + { ++ if (TEST_FAIL()) ++ return -1; ++ + struct mbedtls_sha512_context ctx; + mbedtls_sha512_init(&ctx); + #if MBEDTLS_VERSION_MAJOR >= 3 +@@ -375,6 +381,9 @@ int sha384_vector(size_t num_elem, const + #include <mbedtls/sha256.h> + int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) + { ++ if (TEST_FAIL()) ++ return -1; ++ + struct mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + #if MBEDTLS_VERSION_MAJOR >= 3 +@@ -397,6 +406,9 @@ int sha256_vector(size_t num_elem, const + #include <mbedtls/sha1.h> + int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) + { ++ if (TEST_FAIL()) ++ return -1; ++ + struct mbedtls_sha1_context ctx; + mbedtls_sha1_init(&ctx); + #if MBEDTLS_VERSION_MAJOR >= 3 +@@ -419,6 +431,9 @@ int sha1_vector(size_t num_elem, const u + #include <mbedtls/md5.h> + int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) + { ++ if (TEST_FAIL()) ++ return -1; ++ + struct mbedtls_md5_context ctx; + mbedtls_md5_init(&ctx); + #if MBEDTLS_VERSION_MAJOR >= 3 +@@ -441,6 +456,9 @@ int md5_vector(size_t num_elem, const u8 + #include <mbedtls/md4.h> + int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) + { ++ if (TEST_FAIL()) ++ return -1; ++ + struct mbedtls_md4_context ctx; + mbedtls_md4_init(&ctx); + mbedtls_md4_starts_ret(&ctx); +@@ -460,6 +478,9 @@ static int hmac_vector(const u8 *key, si + const u8 *addr[], const size_t *len, u8 *mac, + mbedtls_md_type_t md_type) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1) != 0){ +@@ -571,6 +592,9 @@ static int hmac_kdf_expand(const u8 *prk + const char *label, const u8 *info, size_t info_len, + u8 *okm, size_t okm_len, mbedtls_md_type_t md_type) + { ++ if (TEST_FAIL()) ++ return -1; ++ + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type); + #ifdef MBEDTLS_HKDF_C + if (label == NULL) /* RFC 5869 HKDF-Expand when (label == NULL) */ +@@ -663,6 +687,9 @@ static int hmac_prf_bits(const u8 *key, + const u8 *data, size_t data_len, u8 *buf, + size_t buf_len_bits, mbedtls_md_type_t md_type) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type); +@@ -938,6 +965,9 @@ int pbkdf2_sha1(const char *passphrase, + + static void *aes_crypt_init_mode(const u8 *key, size_t len, int mode) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + mbedtls_aes_context *aes = os_malloc(sizeof(*aes)); + if (!aes) + return NULL; +@@ -996,6 +1026,9 @@ void aes_decrypt_deinit(void *ctx) + /* aes-wrap.c */ + int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_nist_kw_context ctx; + mbedtls_nist_kw_init(&ctx); + size_t olen; +@@ -1010,6 +1043,9 @@ int aes_wrap(const u8 *kek, size_t kek_l + /* aes-unwrap.c */ + int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_nist_kw_context ctx; + mbedtls_nist_kw_init(&ctx); + size_t olen; +@@ -1041,6 +1077,9 @@ int omac1_aes_vector( + const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_cipher_type_t cipher_type; + switch (key_len) { + case 16: cipher_type = MBEDTLS_CIPHER_AES_128_ECB; break; +@@ -1103,6 +1142,9 @@ int omac1_aes_256(const u8 *key, const u + /* aes-encblock.c */ + int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_aes_context aes; + mbedtls_aes_init(&aes); + int ret = mbedtls_aes_setkey_enc(&aes, key, 128) +@@ -1118,6 +1160,9 @@ int aes_128_encrypt_block(const u8 *key, + int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce, + u8 *data, size_t data_len) + { ++ if (TEST_FAIL()) ++ return -1; ++ + unsigned char counter[MBEDTLS_AES_BLOCK_SIZE]; + unsigned char stream_block[MBEDTLS_AES_BLOCK_SIZE]; + os_memcpy(counter, nonce, MBEDTLS_AES_BLOCK_SIZE);/*(must be writable)*/ +@@ -1160,11 +1205,17 @@ static int aes_128_cbc_oper(const u8 *ke + + int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_ENCRYPT); + } + + int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_DECRYPT); + } + +@@ -1407,6 +1458,10 @@ int crypto_hash_finish(struct crypto_has + } + mbedtls_md_free(mctx); + os_free(mctx); ++ ++ if (TEST_FAIL()) ++ return -1; ++ + return 0; + } + +@@ -1421,6 +1476,9 @@ int crypto_hash_finish(struct crypto_has + + struct crypto_bignum *crypto_bignum_init(void) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + mbedtls_mpi *bn = os_malloc(sizeof(*bn)); + if (bn) + mbedtls_mpi_init(bn); +@@ -1429,6 +1487,9 @@ struct crypto_bignum *crypto_bignum_init + + struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + mbedtls_mpi *bn = os_malloc(sizeof(*bn)); + if (bn) { + mbedtls_mpi_init(bn); +@@ -1442,6 +1503,9 @@ struct crypto_bignum *crypto_bignum_init + + struct crypto_bignum *crypto_bignum_init_uint(unsigned int val) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + #if 0 /*(hostap use of this interface passes int, not uint)*/ + val = host_to_be32(val); + return crypto_bignum_init_set((const u8 *)&val, sizeof(val)); +@@ -1467,6 +1531,9 @@ void crypto_bignum_deinit(struct crypto_ + int crypto_bignum_to_bin(const struct crypto_bignum *a, + u8 *buf, size_t buflen, size_t padlen) + { ++ if (TEST_FAIL()) ++ return -1; ++ + size_t n = mbedtls_mpi_size((mbedtls_mpi *)a); + if (n < padlen) + n = padlen; +@@ -1477,6 +1544,9 @@ int crypto_bignum_to_bin(const struct cr + + int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m) + { ++ if (TEST_FAIL()) ++ return -1; ++ + /*assert(r != m);*//* r must not be same as m for mbedtls_mpi_random()*/ + #if MBEDTLS_VERSION_NUMBER >= 0x021B0000 /* mbedtls 2.27.0 */ + return mbedtls_mpi_random((mbedtls_mpi *)r, 0, (mbedtls_mpi *)m, +@@ -1513,6 +1583,9 @@ int crypto_bignum_exptmod(const struct c + const struct crypto_bignum *c, + struct crypto_bignum *d) + { ++ if (TEST_FAIL()) ++ return -1; ++ + /* (check if input params match d; d is the result) */ + /* (a == d) is ok in current mbedtls implementation */ + if (b == d || c == d) { /*(not ok; store result in intermediate)*/ +@@ -1540,6 +1613,9 @@ int crypto_bignum_inverse(const struct c + const struct crypto_bignum *b, + struct crypto_bignum *c) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return mbedtls_mpi_inv_mod((mbedtls_mpi *)c, + (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) ? -1 : 0; +@@ -1549,6 +1625,9 @@ int crypto_bignum_sub(const struct crypt + const struct crypto_bignum *b, + struct crypto_bignum *c) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return mbedtls_mpi_sub_mpi((mbedtls_mpi *)c, + (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) ? -1 : 0; +@@ -1558,6 +1637,9 @@ int crypto_bignum_div(const struct crypt + const struct crypto_bignum *b, + struct crypto_bignum *c) + { ++ if (TEST_FAIL()) ++ return -1; ++ + /*(most current use of this crypto.h interface has a == c (result), + * so store result in an intermediate to avoid overwritten input)*/ + mbedtls_mpi R; +@@ -1575,6 +1657,9 @@ int crypto_bignum_addmod(const struct cr + const struct crypto_bignum *c, + struct crypto_bignum *d) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return mbedtls_mpi_add_mpi((mbedtls_mpi *)d, + (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) +@@ -1588,6 +1673,9 @@ int crypto_bignum_mulmod(const struct cr + const struct crypto_bignum *c, + struct crypto_bignum *d) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return mbedtls_mpi_mul_mpi((mbedtls_mpi *)d, + (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) +@@ -1600,6 +1688,9 @@ int crypto_bignum_sqrmod(const struct cr + const struct crypto_bignum *b, + struct crypto_bignum *c) + { ++ if (TEST_FAIL()) ++ return -1; ++ + #if 1 + return crypto_bignum_mulmod(a, a, b, c); + #else +@@ -1650,6 +1741,9 @@ int crypto_bignum_is_odd(const struct cr + int crypto_bignum_legendre(const struct crypto_bignum *a, + const struct crypto_bignum *p) + { ++ if (TEST_FAIL()) ++ return -2; ++ + /* Security Note: + * mbedtls_mpi_exp_mod() is not documented to run in constant time, + * though mbedtls/library/bignum.c uses constant_time_internal.h funcs. +@@ -1702,6 +1796,9 @@ int crypto_mod_exp(const u8 *base, size_ + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) + { ++ if (TEST_FAIL()) ++ return -1; ++ + mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result; + mbedtls_mpi_init(&bn_base); + mbedtls_mpi_init(&bn_exp); +@@ -1769,6 +1866,9 @@ static int crypto_mbedtls_dh_init_public + int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, + u8 *pubkey) + { ++ if (TEST_FAIL()) ++ return -1; ++ + #if 0 /*(crypto_dh_init() duplicated (and identical) in crypto_*.c modules)*/ + size_t pubkey_len, pad; + +@@ -1810,6 +1910,9 @@ int crypto_dh_derive_secret(u8 generator + const u8 *pubkey, size_t pubkey_len, + u8 *secret, size_t *len) + { ++ if (TEST_FAIL()) ++ return -1; ++ + #if 0 + if (pubkey_len > prime_len || + (pubkey_len == prime_len && +@@ -2512,6 +2615,9 @@ const struct crypto_ec_point * crypto_ec + + struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + mbedtls_ecp_point *p = os_malloc(sizeof(*p)); + if (p != NULL) + mbedtls_ecp_point_init(p); +@@ -2536,6 +2642,9 @@ int crypto_ec_point_x(struct crypto_ec * + int crypto_ec_point_to_bin(struct crypto_ec *e, + const struct crypto_ec_point *point, u8 *x, u8 *y) + { ++ if (TEST_FAIL()) ++ return -1; ++ + /* crypto.h documents crypto_ec_point_to_bin() output is big-endian */ + size_t len = CRYPTO_EC_plen(e); + if (x) { +@@ -2563,6 +2672,9 @@ int crypto_ec_point_to_bin(struct crypto + struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, + const u8 *val) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + size_t len = CRYPTO_EC_plen(e); + mbedtls_ecp_point *p = os_malloc(sizeof(*p)); + u8 buf[1+MBEDTLS_MPI_MAX_SIZE*2]; +@@ -2615,6 +2727,9 @@ int crypto_ec_point_add(struct crypto_ec + const struct crypto_ec_point *b, + struct crypto_ec_point *c) + { ++ if (TEST_FAIL()) ++ return -1; ++ + /* mbedtls does not provide an mbedtls_ecp_point add function */ + mbedtls_mpi one; + mbedtls_mpi_init(&one); +@@ -2631,6 +2746,9 @@ int crypto_ec_point_mul(struct crypto_ec + const struct crypto_bignum *b, + struct crypto_ec_point *res) + { ++ if (TEST_FAIL()) ++ return -1; ++ + return mbedtls_ecp_mul( + (mbedtls_ecp_group *)e, (mbedtls_ecp_point *)res, + (const mbedtls_mpi *)b, (const mbedtls_ecp_point *)p, +@@ -2639,6 +2757,9 @@ int crypto_ec_point_mul(struct crypto_ec + + int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) + { ++ if (TEST_FAIL()) ++ return -1; ++ + if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e) + == MBEDTLS_ECP_TYPE_MONTGOMERY) { + /* e.g. MBEDTLS_ECP_DP_CURVE25519 and MBEDTLS_ECP_DP_CURVE448 */ +@@ -2751,6 +2872,9 @@ struct crypto_bignum * + crypto_ec_point_compute_y_sqr(struct crypto_ec *e, + const struct crypto_bignum *x) + { ++ if (TEST_FAIL()) ++ return NULL; ++ + mbedtls_mpi *y2 = os_malloc(sizeof(*y2)); + if (y2 == NULL) + return NULL; diff --git a/package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch b/package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch new file mode 100644 index 00000000000..0c29432d3f8 --- /dev/null +++ b/package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch @@ -0,0 +1,91 @@ +The code for hostapd-mbedtls did not work when used for OWE association. + +When handling association requests, the buffer offsets and length assumptions were incorrect, leading to never calculating the y point, thus denying association. + +Also when crafting the association response, the buffer contained the trailing key-type. + +Fix up both issues to adhere to the specification and make hostapd-mbedtls work with the OWE security type. + +--- a/src/crypto/crypto_mbedtls.c ++++ b/src/crypto/crypto_mbedtls.c +@@ -2299,25 +2299,30 @@ struct crypto_ecdh * crypto_ecdh_init2(i + struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) + { + mbedtls_ecp_group *grp = &ecdh->grp; +- size_t len = CRYPTO_EC_plen(grp); ++ size_t prime_len = CRYPTO_EC_plen(grp); ++ size_t output_len = prime_len; ++ u8 output_offset = 0; ++ u8 buf[256]; ++ + #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED + /* len */ + #endif + #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED +- if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) +- len = inc_y ? len*2+1 : len+1; ++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { ++ output_len = inc_y ? prime_len * 2 + 1 : prime_len + 1; ++ output_offset = 1; ++ } + #endif +- struct wpabuf *buf = wpabuf_alloc(len); +- if (buf == NULL) ++ ++ if (output_len > sizeof(buf)) + return NULL; ++ + inc_y = inc_y ? MBEDTLS_ECP_PF_UNCOMPRESSED : MBEDTLS_ECP_PF_COMPRESSED; +- if (mbedtls_ecp_point_write_binary(grp, &ecdh->Q, inc_y, &len, +- wpabuf_mhead_u8(buf), len) == 0) { +- wpabuf_put(buf, len); +- return buf; ++ if (mbedtls_ecp_point_write_binary(grp, &ecdh->Q, inc_y, &output_len, ++ buf, output_len) == 0) { ++ return wpabuf_alloc_copy(buf + output_offset, output_len - output_offset); + } + +- wpabuf_free(buf); + return NULL; + } + +@@ -2379,10 +2384,7 @@ struct wpabuf * crypto_ecdh_set_peerkey( + os_memcpy(buf+2, key, len); + } + len >>= 1; /*(repurpose len to prime_len)*/ +- } +- else if (key[0] == 0x02 || key[0] == 0x03) { /* (inc_y == 0) */ +- --len; /*(repurpose len to prime_len)*/ +- ++ } else { /* (inc_y == 0) */ + /* mbedtls_ecp_point_read_binary() does not currently support + * MBEDTLS_ECP_PF_COMPRESSED format (buf[1] = 0x02 or 0x03) + * (returns MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) */ +@@ -2390,22 +2392,21 @@ struct wpabuf * crypto_ecdh_set_peerkey( + /* derive y, amend buf[] with y for UNCOMPRESSED format */ + if (sizeof(buf)-2 < len*2 || len == 0) + return NULL; ++ + buf[0] = (u8)(1+len*2); + buf[1] = 0x04; ++ os_memcpy(buf+2, key, len); ++ + mbedtls_mpi bn; + mbedtls_mpi_init(&bn); +- int ret = mbedtls_mpi_read_binary(&bn, key+1, len) +- || crypto_mbedtls_short_weierstrass_derive_y(grp, &bn, +- key[0] & 1) ++ int ret = mbedtls_mpi_read_binary(&bn, key, len) ++ || crypto_mbedtls_short_weierstrass_derive_y(grp, &bn, 0) + || mbedtls_mpi_write_binary(&bn, buf+2+len, len); + mbedtls_mpi_free(&bn); + if (ret != 0) + return NULL; + } + +- if (key[0] == 0) /*(repurpose len to prime_len)*/ +- len = CRYPTO_EC_plen(grp); +- + if (mbedtls_ecdh_read_public(&ecdh->ctx, buf, buf[0]+1)) + return NULL; + } diff --git a/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch b/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch new file mode 100644 index 00000000000..e967cff427e --- /dev/null +++ b/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch @@ -0,0 +1,1358 @@ +From f24933dc175e0faf44a3cce3330c256a59649ca6 Mon Sep 17 00:00:00 2001 +From: Glenn Strauss <gstrauss@gluelogic.com> +Date: Tue, 19 Jul 2022 23:01:17 -0400 +Subject: [PATCH 4/7] tests/Makefile make run-tests with CONFIG_TLS=... + +add test-crypto_module.c to run crypto_module_tests() + +adjust some tests/hwsim/*.py for mbed TLS (work in progress) + +option to build and run-tests with CONFIG_TLS=internal # (default) +$ cd tests; make clean +$ make run-tests + +option to build and run-tests with CONFIG_TLS=gnutls +$ cd tests; make clean CONFIG_TLS=gnutls +$ make run-tests CONFIG_TLS=gnutls + +option to build and run-tests with CONFIG_TLS=mbedtls +$ cd tests; make clean CONFIG_TLS=mbedtls +$ make run-tests CONFIG_TLS=mbedtls + +option to build and run-tests with CONFIG_TLS=openssl +$ cd tests; make clean CONFIG_TLS=openssl +$ make run-tests CONFIG_TLS=openssl + +option to build and run-tests with CONFIG_TLS=wolfssl +$ cd tests; make clean CONFIG_TLS=wolfssl +$ make run-tests CONFIG_TLS=wolfssl + +RFE: Makefile logic for crypto objects should be centralized + instead of being duplicated in hostapd/Makefile, + wpa_supplicant/Makefile, src/crypto/Makefile, + tests/Makefile, ... + +Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> +--- + hostapd/Makefile | 6 + + src/crypto/Makefile | 129 ++++++++++++++++++++- + src/crypto/crypto_module_tests.c | 134 ++++++++++++++++++++++ + src/tls/Makefile | 11 ++ + tests/Makefile | 75 +++++++++--- + tests/hwsim/example-hostapd.config | 11 +- + tests/hwsim/example-wpa_supplicant.config | 12 +- + tests/hwsim/test_ap_eap.py | 114 +++++++++++++----- + tests/hwsim/test_ap_ft.py | 4 +- + tests/hwsim/test_authsrv.py | 9 +- + tests/hwsim/test_dpp.py | 19 ++- + tests/hwsim/test_erp.py | 16 +-- + tests/hwsim/test_fils.py | 5 +- + tests/hwsim/test_pmksa_cache.py | 4 +- + tests/hwsim/test_sae.py | 7 ++ + tests/hwsim/test_suite_b.py | 3 + + tests/hwsim/test_wpas_ctrl.py | 2 +- + tests/hwsim/utils.py | 8 +- + tests/test-crypto_module.c | 16 +++ + tests/test-https.c | 12 +- + tests/test-https_server.c | 12 +- + wpa_supplicant/Makefile | 6 + + 22 files changed, 524 insertions(+), 91 deletions(-) + create mode 100644 tests/test-crypto_module.c + +--- a/hostapd/Makefile ++++ b/hostapd/Makefile +@@ -696,6 +696,7 @@ CFLAGS += -DCONFIG_TLSV12 + endif + + ifeq ($(CONFIG_TLS), wolfssl) ++CFLAGS += -DCONFIG_TLS_WOLFSSL + CONFIG_CRYPTO=wolfssl + ifdef TLS_FUNCS + OBJS += ../src/crypto/tls_wolfssl.o +@@ -716,6 +717,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), openssl) ++CFLAGS += -DCONFIG_TLS_OPENSSL + CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 + CONFIG_CRYPTO=openssl + ifdef TLS_FUNCS +@@ -746,6 +748,7 @@ CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONF + endif + + ifeq ($(CONFIG_TLS), mbedtls) ++CFLAGS += -DCONFIG_TLS_MBEDTLS + ifndef CONFIG_CRYPTO + CONFIG_CRYPTO=mbedtls + endif +@@ -776,6 +779,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), gnutls) ++CFLAGS += -DCONFIG_TLS_GNUTLS + ifndef CONFIG_CRYPTO + # default to libgcrypt + CONFIG_CRYPTO=gnutls +@@ -806,6 +810,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), internal) ++CFLAGS += -DCONFIG_TLS_INTERNAL + ifndef CONFIG_CRYPTO + CONFIG_CRYPTO=internal + endif +@@ -884,6 +889,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), linux) ++CFLAGS += -DCONFIG_TLS_INTERNAL + OBJS += ../src/crypto/crypto_linux.o + ifdef TLS_FUNCS + OBJS += ../src/crypto/crypto_internal-rsa.o +--- a/src/crypto/Makefile ++++ b/src/crypto/Makefile +@@ -1,10 +1,121 @@ +-CFLAGS += -DCONFIG_CRYPTO_INTERNAL +-CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT +-CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER + #CFLAGS += -DALL_DH_GROUPS + CFLAGS += -DCONFIG_SHA256 + CFLAGS += -DCONFIG_SHA384 ++CFLAGS += -DCONFIG_HMAC_SHA256_KDF + CFLAGS += -DCONFIG_HMAC_SHA384_KDF ++ ++# crypto_module_tests.c ++CFLAGS += -DCONFIG_MODULE_TESTS ++CFLAGS += -DCONFIG_DPP ++#CFLAGS += -DCONFIG_DPP2 ++#CFLAGS += -DCONFIG_DPP3 ++CFLAGS += -DCONFIG_ECC ++CFLAGS += -DCONFIG_MESH ++CFLAGS += -DEAP_PSK ++CFLAGS += -DEAP_FAST ++ ++ifeq ($(CONFIG_TLS),mbedtls) ++ ++# (enable features for 'cd tests; make run-tests CONFIG_TLS=mbedtls') ++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ++CFLAGS += -DCONFIG_DES ++CFLAGS += -DEAP_IKEV2 ++CFLAGS += -DEAP_MSCHAPv2 ++CFLAGS += -DEAP_SIM ++ ++LIB_OBJS = tls_mbedtls.o crypto_mbedtls.o ++LIB_OBJS+= \ ++ aes-eax.o \ ++ aes-siv.o \ ++ dh_groups.o \ ++ milenage.o \ ++ ms_funcs.o ++ ++else ++ifeq ($(CONFIG_TLS),openssl) ++ ++# (enable features for 'cd tests; make run-tests CONFIG_TLS=openssl') ++ifndef CONFIG_TLS_DEFAULT_CIPHERS ++CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" ++endif ++CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" ++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ++CFLAGS += -DEAP_TLS_OPENSSL ++ ++LIB_OBJS = tls_openssl.o fips_prf_openssl.o crypto_openssl.o ++LIB_OBJS+= \ ++ aes-ctr.o \ ++ aes-eax.o \ ++ aes-encblock.o \ ++ aes-siv.o \ ++ dh_groups.o \ ++ milenage.o \ ++ ms_funcs.o \ ++ sha1-prf.o \ ++ sha1-tlsprf.o \ ++ sha1-tprf.o \ ++ sha256-kdf.o \ ++ sha256-prf.o \ ++ sha256-tlsprf.o ++ ++else ++ifeq ($(CONFIG_TLS),wolfssl) ++ ++# (wolfssl libraries must be built with ./configure --enable-wpas) ++# (enable features for 'cd tests; make run-tests CONFIG_TLS=wolfssl') ++CFLAGS += -DWOLFSSL_DER_LOAD ++CFLAGS += -DCONFIG_DES ++ ++LIB_OBJS = tls_wolfssl.o fips_prf_wolfssl.o crypto_wolfssl.o ++LIB_OBJS+= \ ++ aes-ctr.o \ ++ aes-eax.o \ ++ aes-encblock.o \ ++ aes-siv.o \ ++ dh_groups.o \ ++ milenage.o \ ++ ms_funcs.o \ ++ sha1-prf.o \ ++ sha1-tlsprf.o \ ++ sha1-tprf.o \ ++ sha256-kdf.o \ ++ sha256-prf.o \ ++ sha256-tlsprf.o ++ ++else ++ifeq ($(CONFIG_TLS),gnutls) ++ ++# (enable features for 'cd tests; make run-tests CONFIG_TLS=gnutls') ++LIB_OBJS = tls_gnutls.o crypto_gnutls.o ++LIB_OBJS+= \ ++ aes-cbc.o \ ++ aes-ctr.o \ ++ aes-eax.o \ ++ aes-encblock.o \ ++ aes-omac1.o \ ++ aes-siv.o \ ++ aes-unwrap.o \ ++ aes-wrap.o \ ++ dh_group5.o \ ++ dh_groups.o \ ++ milenage.o \ ++ ms_funcs.o \ ++ rc4.o \ ++ sha1-pbkdf2.o \ ++ sha1-prf.o \ ++ fips_prf_internal.o \ ++ sha1-internal.o \ ++ sha1-tlsprf.o \ ++ sha1-tprf.o \ ++ sha256-kdf.o \ ++ sha256-prf.o \ ++ sha256-tlsprf.o ++ ++else ++ ++CFLAGS += -DCONFIG_CRYPTO_INTERNAL ++CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT ++CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER + CFLAGS += -DCONFIG_INTERNAL_SHA384 + + LIB_OBJS= \ +@@ -13,7 +124,6 @@ LIB_OBJS= \ + aes-ctr.o \ + aes-eax.o \ + aes-encblock.o \ +- aes-gcm.o \ + aes-internal.o \ + aes-internal-dec.o \ + aes-internal-enc.o \ +@@ -37,6 +147,7 @@ LIB_OBJS= \ + sha1-tlsprf.o \ + sha1-tprf.o \ + sha256.o \ ++ sha256-kdf.o \ + sha256-prf.o \ + sha256-tlsprf.o \ + sha256-internal.o \ +@@ -53,6 +164,16 @@ LIB_OBJS += crypto_internal-modexp.o + LIB_OBJS += crypto_internal-rsa.o + LIB_OBJS += tls_internal.o + LIB_OBJS += fips_prf_internal.o ++ ++endif ++endif ++endif ++endif ++ ++ ++# (used by wlantest/{bip,gcmp,rx_mgmt}.c and tests/test-aes.c) ++LIB_OBJS += aes-gcm.o ++ + ifndef TEST_FUZZ + LIB_OBJS += random.o + endif +--- a/src/crypto/crypto_module_tests.c ++++ b/src/crypto/crypto_module_tests.c +@@ -2469,6 +2469,139 @@ static int test_hpke(void) + } + + ++static int test_ecc(void) ++{ ++#ifdef CONFIG_ECC ++#ifndef CONFIG_TLS_INTERNAL ++#ifndef CONFIG_TLS_GNUTLS ++#if defined(CONFIG_TLS_MBEDTLS) \ ++ || defined(CONFIG_TLS_OPENSSL) \ ++ || defined(CONFIG_TLS_WOLFSSL) ++ wpa_printf(MSG_INFO, "Testing ECC"); ++ /* Note: some tests below are valid on supported Short Weierstrass ++ * curves, but not on Montgomery curves (e.g. IKE groups 31 and 32) ++ * (e.g. deriving and comparing y^2 test below not valid on Montgomery) ++ */ ++#ifdef CONFIG_TLS_MBEDTLS ++ const int grps[] = {19, 20, 21, 25, 26, 28}; ++#endif ++#ifdef CONFIG_TLS_OPENSSL ++ const int grps[] = {19, 20, 21, 26}; ++#endif ++#ifdef CONFIG_TLS_WOLFSSL ++ const int grps[] = {19, 20, 21, 26}; ++#endif ++ uint32_t i; ++ struct crypto_ec *e = NULL; ++ struct crypto_ec_point *p = NULL, *q = NULL; ++ struct crypto_bignum *x = NULL, *y = NULL; ++#ifdef CONFIG_DPP ++ u8 bin[4096]; ++#endif ++ for (i = 0; i < ARRAY_SIZE(grps); ++i) { ++ e = crypto_ec_init(grps[i]); ++ if (e == NULL ++ || crypto_ec_prime_len(e) == 0 ++ || crypto_ec_prime_len_bits(e) == 0 ++ || crypto_ec_order_len(e) == 0 ++ || crypto_ec_get_prime(e) == NULL ++ || crypto_ec_get_order(e) == NULL ++ || crypto_ec_get_a(e) == NULL ++ || crypto_ec_get_b(e) == NULL ++ || crypto_ec_get_generator(e) == NULL) { ++ break; ++ } ++#ifdef CONFIG_DPP ++ struct crypto_ec_key *key = crypto_ec_key_gen(grps[i]); ++ if (key == NULL) ++ break; ++ p = crypto_ec_key_get_public_key(key); ++ q = crypto_ec_key_get_public_key(key); ++ crypto_ec_key_deinit(key); ++ if (p == NULL || q == NULL) ++ break; ++ if (!crypto_ec_point_is_on_curve(e, p)) ++ break; ++ ++ /* inverted point should not match original; ++ * double-invert should match */ ++ if (crypto_ec_point_invert(e, q) != 0 ++ || crypto_ec_point_cmp(e, p, q) == 0 ++ || crypto_ec_point_invert(e, q) != 0 ++ || crypto_ec_point_cmp(e, p, q) != 0) { ++ break; ++ } ++ ++ /* crypto_ec_point_to_bin() and crypto_ec_point_from_bin() ++ * imbalanced interfaces? */ ++ size_t prime_len = crypto_ec_prime_len(e); ++ if (prime_len * 2 > sizeof(bin)) ++ break; ++ if (crypto_ec_point_to_bin(e, p, bin, bin+prime_len) != 0) ++ break; ++ struct crypto_ec_point *tmp = crypto_ec_point_from_bin(e, bin); ++ if (tmp == NULL) ++ break; ++ if (crypto_ec_point_cmp(e, p, tmp) != 0) { ++ crypto_ec_point_deinit(tmp, 0); ++ break; ++ } ++ crypto_ec_point_deinit(tmp, 0); ++ ++ x = crypto_bignum_init(); ++ y = crypto_bignum_init_set(bin+prime_len, prime_len); ++ if (x == NULL || y == NULL || crypto_ec_point_x(e, p, x) != 0) ++ break; ++ struct crypto_bignum *y2 = crypto_ec_point_compute_y_sqr(e, x); ++ if (y2 == NULL) ++ break; ++ if (crypto_bignum_sqrmod(y, crypto_ec_get_prime(e), y) != 0 ++ || crypto_bignum_cmp(y, y2) != 0) { ++ crypto_bignum_deinit(y2, 0); ++ break; ++ } ++ crypto_bignum_deinit(y2, 0); ++ crypto_bignum_deinit(x, 0); ++ crypto_bignum_deinit(y, 0); ++ x = NULL; ++ y = NULL; ++ ++ x = crypto_bignum_init(); ++ if (x == NULL) ++ break; ++ if (crypto_bignum_rand(x, crypto_ec_get_prime(e)) != 0) ++ break; ++ crypto_bignum_deinit(x, 0); ++ x = NULL; ++ ++ crypto_ec_point_deinit(p, 0); ++ p = NULL; ++ crypto_ec_point_deinit(q, 0); ++ q = NULL; ++#endif /* CONFIG_DPP */ ++ crypto_ec_deinit(e); ++ e = NULL; ++ } ++ if (i != ARRAY_SIZE(grps)) { ++ crypto_bignum_deinit(x, 0); ++ crypto_bignum_deinit(y, 0); ++ crypto_ec_point_deinit(p, 0); ++ crypto_ec_point_deinit(q, 0); ++ crypto_ec_deinit(e); ++ wpa_printf(MSG_INFO, ++ "ECC test case failed tls_id:%d", grps[i]); ++ return -1; ++ } ++ ++ wpa_printf(MSG_INFO, "ECC test cases passed"); ++#endif ++#endif /* !CONFIG_TLS_GNUTLS */ ++#endif /* !CONFIG_TLS_INTERNAL */ ++#endif /* CONFIG_ECC */ ++ return 0; ++} ++ ++ + static int test_ms_funcs(void) + { + #ifndef CONFIG_FIPS +@@ -2590,6 +2723,7 @@ int crypto_module_tests(void) + test_fips186_2_prf() || + test_extract_expand_hkdf() || + test_hpke() || ++ test_ecc() || + test_ms_funcs()) + ret = -1; + +--- a/src/tls/Makefile ++++ b/src/tls/Makefile +@@ -1,3 +1,10 @@ ++LIB_OBJS= asn1.o ++ ++ifneq ($(CONFIG_TLS),gnutls) ++ifneq ($(CONFIG_TLS),mbedtls) ++ifneq ($(CONFIG_TLS),openssl) ++ifneq ($(CONFIG_TLS),wolfssl) ++ + CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH + CFLAGS += -DCONFIG_CRYPTO_INTERNAL + CFLAGS += -DCONFIG_TLSV11 +@@ -21,5 +28,9 @@ LIB_OBJS= \ + tlsv1_server_read.o \ + tlsv1_server_write.o \ + x509v3.o ++endif ++endif ++endif ++endif + + include ../lib.rules +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -1,8 +1,10 @@ +-ALL=test-base64 test-md4 test-milenage \ +- test-rsa-sig-ver \ +- test-sha1 \ +- test-https test-https_server \ +- test-sha256 test-aes test-x509v3 test-list test-rc4 ++RUN_TESTS= \ ++ test-list \ ++ test-md4 test-rc4 test-sha1 test-sha256 \ ++ test-milenage test-aes \ ++ test-crypto_module ++ ++ALL=$(RUN_TESTS) test-base64 test-https test-https_server + + include ../src/build.rules + +@@ -24,13 +26,27 @@ CFLAGS += -DCONFIG_IEEE80211R_AP + CFLAGS += -DCONFIG_IEEE80211R + CFLAGS += -DCONFIG_TDLS + ++# test-crypto_module ++CFLAGS += -DCONFIG_MODULE_TESTS ++CFLAGS += -DCONFIG_DPP ++#CFLAGS += -DCONFIG_DPP2 ++#CFLAGS += -DCONFIG_DPP3 ++CFLAGS += -DCONFIG_ECC ++CFLAGS += -DCONFIG_HMAC_SHA256_KDF ++CFLAGS += -DCONFIG_HMAC_SHA384_KDF ++CFLAGS += -DCONFIG_MESH ++CFLAGS += -DCONFIG_SHA256 ++CFLAGS += -DCONFIG_SHA384 ++CFLAGS += -DEAP_PSK ++CFLAGS += -DEAP_FAST ++ + CFLAGS += -I../src + CFLAGS += -I../src/utils + + SLIBS = ../src/utils/libutils.a + +-DLIBS = ../src/crypto/libcrypto.a \ +- ../src/tls/libtls.a ++DLIBS = ../src/tls/libtls.a \ ++ ../src/crypto/libcrypto.a + + _OBJS_VAR := LLIBS + include ../src/objs.mk +@@ -42,12 +58,43 @@ include ../src/objs.mk + LIBS = $(SLIBS) $(DLIBS) + LLIBS = -Wl,--start-group $(DLIBS) -Wl,--end-group $(SLIBS) + ++ifeq ($(CONFIG_TLS),mbedtls) ++CFLAGS += -DCONFIG_TLS_MBEDTLS ++LLIBS += -lmbedtls -lmbedx509 -lmbedcrypto ++else ++ifeq ($(CONFIG_TLS),openssl) ++CFLAGS += -DCONFIG_TLS_OPENSSL ++LLIBS += -lssl -lcrypto ++else ++ifeq ($(CONFIG_TLS),gnutls) ++CFLAGS += -DCONFIG_TLS_GNUTLS ++LLIBS += -lgnutls -lgpg-error -lgcrypt ++else ++ifeq ($(CONFIG_TLS),wolfssl) ++CFLAGS += -DCONFIG_TLS_WOLFSSL ++LLIBS += -lwolfssl -lm ++else ++CFLAGS += -DCONFIG_TLS_INTERNAL ++CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER ++ALL += test-rsa-sig-ver ++ALL += test-x509v3 ++clean-config_tls_internal: ++ rm -f test_x509v3_nist.out.* ++ rm -f test_x509v3_nist2.out.* ++endif ++endif ++endif ++endif ++ + # glibc < 2.17 needs -lrt for clock_gettime() + LLIBS += -lrt + + test-aes: $(call BUILDOBJ,test-aes.o) $(LIBS) + $(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS) + ++test-crypto_module: $(call BUILDOBJ,test-crypto_module.o) $(LIBS) ++ $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS) ++ + test-base64: $(call BUILDOBJ,test-base64.o) $(LIBS) + $(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS) + +@@ -83,17 +130,11 @@ test-x509v3: $(call BUILDOBJ,test-x509v3 + + + run-tests: $(ALL) +- ./test-aes +- ./test-list +- ./test-md4 +- ./test-milenage +- ./test-rsa-sig-ver +- ./test-sha1 +- ./test-sha256 ++ @set -ex; for i in $(RUN_TESTS); do ./$$i; done + @echo + @echo All tests completed successfully. + +-clean: common-clean ++clean: common-clean clean-config_tls_internal + rm -f *~ +- rm -f test_x509v3_nist.out.* +- rm -f test_x509v3_nist2.out.* ++ ++.PHONY: run-tests clean-config_tls_internal +--- a/tests/hwsim/example-hostapd.config ++++ b/tests/hwsim/example-hostapd.config +@@ -34,15 +34,7 @@ CONFIG_EAP_TNC=y + CFLAGS += -DTNC_CONFIG_FILE=\"tnc/tnc_config\" + LIBS += -rdynamic + CONFIG_EAP_UNAUTH_TLS=y +-ifeq ($(CONFIG_TLS), openssl) +-CONFIG_EAP_PWD=y +-endif +-ifeq ($(CONFIG_TLS), wolfssl) +-CONFIG_EAP_PWD=y +-endif +-ifeq ($(CONFIG_TLS), mbedtls) +-CONFIG_EAP_PWD=y +-endif ++CONFIG_EAP_PWD=$(if $(filter openssl wolfssl mbedtls,$(CONFIG_TLS)),y,) + CONFIG_EAP_EKE=y + CONFIG_PKCS12=y + CONFIG_RADIUS_SERVER=y +@@ -89,6 +81,7 @@ CFLAGS += -DCONFIG_RADIUS_TEST + CONFIG_MODULE_TESTS=y + + CONFIG_SUITEB=y ++CONFIG_SUITEB192=$(if $(filter openssl mbedtls,$(CONFIG_TLS)),y,) + + # AddressSanitizer (ASan) can be enabled by uncommenting the following lines. + # This can be used as a more efficient memory error detector than valgrind +--- a/tests/hwsim/example-wpa_supplicant.config ++++ b/tests/hwsim/example-wpa_supplicant.config +@@ -35,16 +35,7 @@ LIBS += -rdynamic + CONFIG_EAP_FAST=y + CONFIG_EAP_TEAP=y + CONFIG_EAP_IKEV2=y +- +-ifeq ($(CONFIG_TLS), openssl) +-CONFIG_EAP_PWD=y +-endif +-ifeq ($(CONFIG_TLS), wolfssl) +-CONFIG_EAP_PWD=y +-endif +-ifeq ($(CONFIG_TLS), mbedtls) +-CONFIG_EAP_PWD=y +-endif ++CONFIG_EAP_PWD=$(if $(filter openssl wolfssl mbedtls,$(CONFIG_TLS)),y,) + + CONFIG_USIM_SIMULATOR=y + CONFIG_SIM_SIMULATOR=y +@@ -137,6 +128,7 @@ CONFIG_TESTING_OPTIONS=y + CONFIG_MODULE_TESTS=y + + CONFIG_SUITEB=y ++CONFIG_SUITEB192=$(if $(filter openssl mbedtls,$(CONFIG_TLS)),y,) + + # AddressSanitizer (ASan) can be enabled by uncommenting the following lines. + # This can be used as a more efficient memory error detector than valgrind +--- a/tests/hwsim/test_ap_eap.py ++++ b/tests/hwsim/test_ap_eap.py +@@ -42,20 +42,42 @@ def check_eap_capa(dev, method): + res = dev.get_capability("eap") + if method not in res: + raise HwsimSkip("EAP method %s not supported in the build" % method) ++ if method == "FAST" or method == "TEAP": ++ tls = dev.request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("EAP-%s not supported with this TLS library: " % method + tls) + + def check_subject_match_support(dev): + tls = dev.request("GET tls_library") +- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): ++ if tls.startswith("OpenSSL"): ++ return ++ elif tls.startswith("wolfSSL"): ++ return ++ elif tls.startswith("mbed TLS"): ++ return ++ else: + raise HwsimSkip("subject_match not supported with this TLS library: " + tls) + + def check_check_cert_subject_support(dev): + tls = dev.request("GET tls_library") +- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): ++ if tls.startswith("OpenSSL"): ++ return ++ elif tls.startswith("wolfSSL"): ++ return ++ elif tls.startswith("mbed TLS"): ++ return ++ else: + raise HwsimSkip("check_cert_subject not supported with this TLS library: " + tls) + + def check_altsubject_match_support(dev): + tls = dev.request("GET tls_library") +- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): ++ if tls.startswith("OpenSSL"): ++ return ++ elif tls.startswith("wolfSSL"): ++ return ++ elif tls.startswith("mbed TLS"): ++ return ++ else: + raise HwsimSkip("altsubject_match not supported with this TLS library: " + tls) + + def check_domain_match(dev): +@@ -70,7 +92,13 @@ def check_domain_suffix_match(dev): + + def check_domain_match_full(dev): + tls = dev.request("GET tls_library") +- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): ++ if tls.startswith("OpenSSL"): ++ return ++ elif tls.startswith("wolfSSL"): ++ return ++ elif tls.startswith("mbed TLS"): ++ return ++ else: + raise HwsimSkip("domain_suffix_match requires full match with this TLS library: " + tls) + + def check_cert_probe_support(dev): +@@ -79,8 +107,15 @@ def check_cert_probe_support(dev): + raise HwsimSkip("Certificate probing not supported with this TLS library: " + tls) + + def check_ext_cert_check_support(dev): ++ if not openssl_imported: ++ raise HwsimSkip("OpenSSL python method not available") ++ + tls = dev.request("GET tls_library") +- if not tls.startswith("OpenSSL"): ++ if tls.startswith("OpenSSL"): ++ return ++ elif tls.startswith("mbed TLS"): ++ return ++ else: + raise HwsimSkip("ext_cert_check not supported with this TLS library: " + tls) + + def check_ocsp_support(dev): +@@ -91,14 +126,18 @@ def check_ocsp_support(dev): + # raise HwsimSkip("OCSP not supported with this TLS library: " + tls) + #if tls.startswith("wolfSSL"): + # raise HwsimSkip("OCSP not supported with this TLS library: " + tls) ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("OCSP not supported with this TLS library: " + tls) + + def check_pkcs5_v15_support(dev): + tls = dev.request("GET tls_library") +- if "BoringSSL" in tls or "GnuTLS" in tls: ++ if "BoringSSL" in tls or "GnuTLS" in tls or "mbed TLS" in tls: + raise HwsimSkip("PKCS#5 v1.5 not supported with this TLS library: " + tls) + + def check_tls13_support(dev): + tls = dev.request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("TLS v1.3 not supported") + if "run=OpenSSL 1.1.1" not in tls and "run=OpenSSL 3.0" not in tls and "wolfSSL" not in tls: + raise HwsimSkip("TLS v1.3 not supported") + +@@ -118,11 +157,15 @@ def check_pkcs12_support(dev): + # raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls) + if tls.startswith("wolfSSL"): + raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls) ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls) + + def check_dh_dsa_support(dev): + tls = dev.request("GET tls_library") + if tls.startswith("internal"): + raise HwsimSkip("DH DSA not supported with this TLS library: " + tls) ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("DH DSA not supported with this TLS library: " + tls) + + def check_ec_support(dev): + tls = dev.request("GET tls_library") +@@ -1595,7 +1638,7 @@ def test_ap_wpa2_eap_ttls_pap_subject_ma + eap_connect(dev[0], hapd, "TTLS", "pap user", + anonymous_identity="ttls", password="password", + ca_cert="auth_serv/ca.pem", phase2="auth=PAP", +- subject_match="/C=FI/O=w1.fi/CN=server.w1.fi", ++ check_cert_subject="/C=FI/O=w1.fi/CN=server.w1.fi", + altsubject_match="EMAIL:noone@example.com;DNS:server.w1.fi;URI:http://example.com/") + eap_reauth(dev[0], "TTLS") + +@@ -2830,6 +2873,7 @@ def test_ap_wpa2_eap_tls_neg_domain_matc + + def test_ap_wpa2_eap_tls_neg_subject_match(dev, apdev): + """WPA2-Enterprise negative test - subject mismatch""" ++ check_subject_match_support(dev[0]) + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hostapd.add_ap(apdev[0], params) + dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS", +@@ -2890,6 +2934,7 @@ def test_ap_wpa2_eap_tls_neg_subject_mat + + def test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev): + """WPA2-Enterprise negative test - altsubject mismatch""" ++ check_altsubject_match_support(dev[0]) + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hostapd.add_ap(apdev[0], params) + +@@ -3430,7 +3475,7 @@ def test_ap_wpa2_eap_ikev2_oom(dev, apde + dev[0].request("REMOVE_NETWORK all") + + tls = dev[0].request("GET tls_library") +- if not tls.startswith("wolfSSL"): ++ if not tls.startswith("wolfSSL") and not tls.startswith("mbed TLS"): + tests = [(1, "os_get_random;dh_init")] + else: + tests = [(1, "crypto_dh_init;dh_init")] +@@ -4744,7 +4789,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca + params["private_key"] = "auth_serv/iCA-server/server.key" + hostapd.add_ap(apdev[0], params) + tls = dev[0].request("GET tls_library") +- if "GnuTLS" in tls or "wolfSSL" in tls: ++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls: + ca_cert = "auth_serv/iCA-user/ca-and-root.pem" + client_cert = "auth_serv/iCA-user/user_and_ica.pem" + else: +@@ -4810,6 +4855,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca + run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, "-sha1") + + def run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, md): ++ check_ocsp_support(dev[0]) + params = int_eap_server_params() + params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem" + params["server_cert"] = "auth_serv/iCA-server/server.pem" +@@ -4819,7 +4865,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_ + try: + hostapd.add_ap(apdev[0], params) + tls = dev[0].request("GET tls_library") +- if "GnuTLS" in tls or "wolfSSL" in tls: ++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls: + ca_cert = "auth_serv/iCA-user/ca-and-root.pem" + client_cert = "auth_serv/iCA-user/user_and_ica.pem" + else: +@@ -4855,7 +4901,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_ + try: + hostapd.add_ap(apdev[0], params) + tls = dev[0].request("GET tls_library") +- if "GnuTLS" in tls or "wolfSSL" in tls: ++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls: + ca_cert = "auth_serv/iCA-user/ca-and-root.pem" + client_cert = "auth_serv/iCA-user/user_and_ica.pem" + else: +@@ -4905,7 +4951,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca + try: + hostapd.add_ap(apdev[0], params) + tls = dev[0].request("GET tls_library") +- if "GnuTLS" in tls or "wolfSSL" in tls: ++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls: + ca_cert = "auth_serv/iCA-user/ca-and-root.pem" + client_cert = "auth_serv/iCA-user/user_and_ica.pem" + else: +@@ -4972,7 +5018,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca + + hostapd.add_ap(apdev[0], params) + tls = dev[0].request("GET tls_library") +- if "GnuTLS" in tls or "wolfSSL" in tls: ++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls: + ca_cert = "auth_serv/iCA-user/ca-and-root.pem" + client_cert = "auth_serv/iCA-user/user_and_ica.pem" + else: +@@ -5230,6 +5276,7 @@ def test_ap_wpa2_eap_ttls_server_cert_ek + + def test_ap_wpa2_eap_ttls_server_pkcs12(dev, apdev): + """WPA2-Enterprise using EAP-TTLS and server PKCS#12 file""" ++ check_pkcs12_support(dev[0]) + skip_with_fips(dev[0]) + params = int_eap_server_params() + del params["server_cert"] +@@ -5242,6 +5289,7 @@ def test_ap_wpa2_eap_ttls_server_pkcs12( + + def test_ap_wpa2_eap_ttls_server_pkcs12_extra(dev, apdev): + """EAP-TTLS and server PKCS#12 file with extra certs""" ++ check_pkcs12_support(dev[0]) + skip_with_fips(dev[0]) + params = int_eap_server_params() + del params["server_cert"] +@@ -5264,6 +5312,7 @@ def test_ap_wpa2_eap_ttls_dh_params_serv + + def test_ap_wpa2_eap_ttls_dh_params_dsa_server(dev, apdev): + """WPA2-Enterprise using EAP-TTLS and alternative server dhparams (DSA)""" ++ check_dh_dsa_support(dev[0]) + params = int_eap_server_params() + params["dh_file"] = "auth_serv/dsaparam.pem" + hapd = hostapd.add_ap(apdev[0], params) +@@ -5575,8 +5624,8 @@ def test_ap_wpa2_eap_non_ascii_identity2 + def test_openssl_cipher_suite_config_wpas(dev, apdev): + """OpenSSL cipher suite configuration on wpa_supplicant""" + tls = dev[0].request("GET tls_library") +- if not tls.startswith("OpenSSL"): +- raise HwsimSkip("TLS library is not OpenSSL: " + tls) ++ if not tls.startswith("OpenSSL") and not tls.startswith("mbed TLS"): ++ raise HwsimSkip("TLS library is not OpenSSL or mbed TLS: " + tls) + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hapd = hostapd.add_ap(apdev[0], params) + eap_connect(dev[0], hapd, "TTLS", "pap user", +@@ -5602,14 +5651,14 @@ def test_openssl_cipher_suite_config_wpa + def test_openssl_cipher_suite_config_hapd(dev, apdev): + """OpenSSL cipher suite configuration on hostapd""" + tls = dev[0].request("GET tls_library") +- if not tls.startswith("OpenSSL"): +- raise HwsimSkip("wpa_supplicant TLS library is not OpenSSL: " + tls) ++ if not tls.startswith("OpenSSL") and not tls.startswith("mbed TLS"): ++ raise HwsimSkip("wpa_supplicant TLS library is not OpenSSL or mbed TLS: " + tls) + params = int_eap_server_params() + params['openssl_ciphers'] = "AES256" + hapd = hostapd.add_ap(apdev[0], params) + tls = hapd.request("GET tls_library") +- if not tls.startswith("OpenSSL"): +- raise HwsimSkip("hostapd TLS library is not OpenSSL: " + tls) ++ if not tls.startswith("OpenSSL") and not tls.startswith("mbed TLS"): ++ raise HwsimSkip("hostapd TLS library is not OpenSSL or mbed TLS: " + tls) + eap_connect(dev[0], hapd, "TTLS", "pap user", + anonymous_identity="ttls", password="password", + ca_cert="auth_serv/ca.pem", phase2="auth=PAP") +@@ -6051,13 +6100,17 @@ def test_ap_wpa2_eap_tls_versions(dev, a + check_tls_ver(dev[0], hapd, + "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", + "TLSv1.2") +- elif tls.startswith("internal"): ++ elif tls.startswith("internal") or tls.startswith("mbed TLS"): + check_tls_ver(dev[0], hapd, + "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", "TLSv1.2") +- check_tls_ver(dev[1], hapd, +- "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=0 tls_disable_tlsv1_2=1", "TLSv1.1") +- check_tls_ver(dev[2], hapd, +- "tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1") ++ if tls.startswith("mbed TLS"): ++ check_tls_ver(dev[2], hapd, ++ "tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1.0") ++ else: ++ check_tls_ver(dev[1], hapd, ++ "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=0 tls_disable_tlsv1_2=1", "TLSv1.1") ++ check_tls_ver(dev[2], hapd, ++ "tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1") + if "run=OpenSSL 1.1.1" in tls or "run=OpenSSL 3.0" in tls: + check_tls_ver(dev[0], hapd, + "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1 tls_disable_tlsv1_3=0", "TLSv1.3") +@@ -6079,6 +6132,11 @@ def test_ap_wpa2_eap_tls_versions_server + tests = [("TLSv1", "[ENABLE-TLSv1.0][DISABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"), + ("TLSv1.1", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"), + ("TLSv1.2", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][ENABLE-TLSv1.2][DISABLE-TLSv1.3]")] ++ tls = dev[0].request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ tests = [#("TLSv1.0", "[ENABLE-TLSv1.0][DISABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"), ++ #("TLSv1.1", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"), ++ ("TLSv1.2", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][ENABLE-TLSv1.2][DISABLE-TLSv1.3]")] + for exp, flags in tests: + hapd.disable() + hapd.set("tls_flags", flags) +@@ -7138,6 +7196,7 @@ def test_ap_wpa2_eap_assoc_rsn(dev, apde + def test_eap_tls_ext_cert_check(dev, apdev): + """EAP-TLS and external server certification validation""" + # With internal server certificate chain validation ++ check_ext_cert_check_support(dev[0]) + id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS", + identity="tls user", + ca_cert="auth_serv/ca.pem", +@@ -7150,6 +7209,7 @@ def test_eap_tls_ext_cert_check(dev, apd + def test_eap_ttls_ext_cert_check(dev, apdev): + """EAP-TTLS and external server certification validation""" + # Without internal server certificate chain validation ++ check_ext_cert_check_support(dev[0]) + id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS", + identity="pap user", anonymous_identity="ttls", + password="password", phase2="auth=PAP", +@@ -7160,6 +7220,7 @@ def test_eap_ttls_ext_cert_check(dev, ap + def test_eap_peap_ext_cert_check(dev, apdev): + """EAP-PEAP and external server certification validation""" + # With internal server certificate chain validation ++ check_ext_cert_check_support(dev[0]) + id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP", + identity="user", anonymous_identity="peap", + ca_cert="auth_serv/ca.pem", +@@ -7170,6 +7231,7 @@ def test_eap_peap_ext_cert_check(dev, ap + + def test_eap_fast_ext_cert_check(dev, apdev): + """EAP-FAST and external server certification validation""" ++ check_ext_cert_check_support(dev[0]) + check_eap_capa(dev[0], "FAST") + # With internal server certificate chain validation + dev[0].request("SET blob fast_pac_auth_ext ") +@@ -7184,10 +7246,6 @@ def test_eap_fast_ext_cert_check(dev, ap + run_ext_cert_check(dev, apdev, id) + + def run_ext_cert_check(dev, apdev, net_id): +- check_ext_cert_check_support(dev[0]) +- if not openssl_imported: +- raise HwsimSkip("OpenSSL python method not available") +- + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hapd = hostapd.add_ap(apdev[0], params) + +--- a/tests/hwsim/test_ap_ft.py ++++ b/tests/hwsim/test_ap_ft.py +@@ -2474,11 +2474,11 @@ def test_ap_ft_ap_oom5(dev, apdev): + # This will fail to roam + dev[0].roam(bssid1, check_bssid=False) + +- with fail_test(hapd1, 1, "sha256_prf_bits;wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"): ++ with fail_test(hapd1, 1, "sha256_prf;wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"): + # This will fail to roam + dev[0].roam(bssid1, check_bssid=False) + +- with fail_test(hapd1, 3, "wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"): ++ with fail_test(hapd1, 2, "wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"): + # This will fail to roam + dev[0].roam(bssid1, check_bssid=False) + +--- a/tests/hwsim/test_authsrv.py ++++ b/tests/hwsim/test_authsrv.py +@@ -156,9 +156,12 @@ def test_authsrv_oom(dev, apdev): + if "FAIL" not in authsrv.request("ENABLE"): + raise Exception("ENABLE succeeded during OOM") + +- with alloc_fail(authsrv, 1, "tls_init;authsrv_init"): +- if "FAIL" not in authsrv.request("ENABLE"): +- raise Exception("ENABLE succeeded during OOM") ++ # tls_mbedtls.c:tls_init() does not alloc memory (no alloc fail trigger) ++ tls = dev[0].request("GET tls_library") ++ if not tls.startswith("mbed TLS"): ++ with alloc_fail(authsrv, 1, "tls_init;authsrv_init"): ++ if "FAIL" not in authsrv.request("ENABLE"): ++ raise Exception("ENABLE succeeded during OOM") + + for count in range(1, 3): + with alloc_fail(authsrv, count, "eap_sim_db_init;authsrv_init"): +--- a/tests/hwsim/test_dpp.py ++++ b/tests/hwsim/test_dpp.py +@@ -39,7 +39,8 @@ def check_dpp_capab(dev, brainpool=False + raise HwsimSkip("DPP not supported") + if brainpool: + tls = dev.request("GET tls_library") +- if (not tls.startswith("OpenSSL") or "run=BoringSSL" in tls) and not tls.startswith("wolfSSL"): ++ if (not tls.startswith("OpenSSL") or "run=BoringSSL" in tls) and not tls.startswith("wolfSSL") \ ++ and not tls.startswith("mbed TLS"): + raise HwsimSkip("Crypto library does not support Brainpool curves: " + tls) + capa = dev.request("GET_CAPABILITY dpp") + ver = 1 +@@ -3892,6 +3893,9 @@ def test_dpp_proto_auth_req_no_i_proto_k + + def test_dpp_proto_auth_req_invalid_i_proto_key(dev, apdev): + """DPP protocol testing - invalid I-proto key in Auth Req""" ++ tls = dev[0].request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key; no response") + run_dpp_proto_auth_req_missing(dev, 66, "Invalid Initiator Protocol Key") + + def test_dpp_proto_auth_req_no_i_nonce(dev, apdev): +@@ -3987,7 +3991,12 @@ def test_dpp_proto_auth_resp_no_r_proto_ + + def test_dpp_proto_auth_resp_invalid_r_proto_key(dev, apdev): + """DPP protocol testing - invalid R-Proto Key in Auth Resp""" +- run_dpp_proto_auth_resp_missing(dev, 67, "Invalid Responder Protocol Key") ++ tls = dev[0].request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ # mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key ++ run_dpp_proto_auth_resp_missing(dev, 67, "Failed to derive ECDH shared secret") ++ else: ++ run_dpp_proto_auth_resp_missing(dev, 67, "Invalid Responder Protocol Key") + + def test_dpp_proto_auth_resp_no_r_nonce(dev, apdev): + """DPP protocol testing - no R-nonce in Auth Resp""" +@@ -4349,11 +4358,17 @@ def test_dpp_proto_pkex_exchange_resp_in + + def test_dpp_proto_pkex_cr_req_invalid_bootstrap_key(dev, apdev): + """DPP protocol testing - invalid Bootstrap Key in PKEX Commit-Reveal Request""" ++ tls = dev[0].request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key; no response") + run_dpp_proto_pkex_req_missing(dev, 47, + "Peer bootstrapping key is invalid") + + def test_dpp_proto_pkex_cr_resp_invalid_bootstrap_key(dev, apdev): + """DPP protocol testing - invalid Bootstrap Key in PKEX Commit-Reveal Response""" ++ tls = dev[0].request("GET tls_library") ++ if tls.startswith("mbed TLS"): ++ raise HwsimSkip("mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key; no response") + run_dpp_proto_pkex_resp_missing(dev, 48, + "Peer bootstrapping key is invalid") + +--- a/tests/hwsim/test_erp.py ++++ b/tests/hwsim/test_erp.py +@@ -12,7 +12,7 @@ import time + + import hostapd + from utils import * +-from test_ap_eap import int_eap_server_params, check_tls13_support ++from test_ap_eap import int_eap_server_params, check_tls13_support, check_eap_capa + from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations + + def test_erp_initiate_reauth_start(dev, apdev): +@@ -276,6 +276,7 @@ def test_erp_radius_eap_methods(dev, apd + params['erp_domain'] = 'example.com' + params['disable_pmksa_caching'] = '1' + hapd = hostapd.add_ap(apdev[0], params) ++ tls = dev[0].request("GET tls_library") + + erp_test(dev[0], hapd, eap="AKA", identity="0232010000000000@example.com", + password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123") +@@ -289,7 +290,7 @@ def test_erp_radius_eap_methods(dev, apd + password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123") + erp_test(dev[0], hapd, eap="EKE", identity="erp-eke@example.com", + password="hello") +- if "FAST" in eap_methods: ++ if "FAST" in eap_methods and check_eap_capa(dev[0], "FAST"): + erp_test(dev[0], hapd, eap="FAST", identity="erp-fast@example.com", + password="password", ca_cert="auth_serv/ca.pem", + phase2="auth=GTC", +@@ -301,13 +302,14 @@ def test_erp_radius_eap_methods(dev, apd + password="password") + erp_test(dev[0], hapd, eap="PAX", identity="erp-pax@example.com", + password_hex="0123456789abcdef0123456789abcdef") +- if "MSCHAPV2" in eap_methods: ++ if "MSCHAPV2" in eap_methods and check_eap_capa(dev[0], "MSCHAPV2"): + erp_test(dev[0], hapd, eap="PEAP", identity="erp-peap@example.com", + password="password", ca_cert="auth_serv/ca.pem", + phase2="auth=MSCHAPV2") +- erp_test(dev[0], hapd, eap="TEAP", identity="erp-teap@example.com", +- password="password", ca_cert="auth_serv/ca.pem", +- phase2="auth=MSCHAPV2", pac_file="blob://teap_pac") ++ if check_eap_capa(dev[0], "TEAP"): ++ erp_test(dev[0], hapd, eap="TEAP", identity="erp-teap@example.com", ++ password="password", ca_cert="auth_serv/ca.pem", ++ phase2="auth=MSCHAPV2", pac_file="blob://teap_pac") + erp_test(dev[0], hapd, eap="PSK", identity="erp-psk@example.com", + password_hex="0123456789abcdef0123456789abcdef") + if "PWD" in eap_methods: +@@ -640,7 +642,7 @@ def test_erp_local_errors(dev, apdev): + dev[0].request("REMOVE_NETWORK all") + dev[0].wait_disconnected() + +- for count in range(1, 6): ++ for count in range(1, 4): + dev[0].request("ERP_FLUSH") + with fail_test(dev[0], count, "hmac_sha256_kdf;eap_peer_erp_init"): + dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS", +--- a/tests/hwsim/test_fils.py ++++ b/tests/hwsim/test_fils.py +@@ -1422,7 +1422,10 @@ def run_fils_sk_pfs(dev, apdev, group, p + check_erp_capa(dev[0]) + + tls = dev[0].request("GET tls_library") +- if not tls.startswith("wolfSSL"): ++ if tls.startswith("mbed TLS"): ++ if int(group) == 27: ++ raise HwsimSkip("Brainpool EC group 27 not supported by mbed TLS") ++ elif not tls.startswith("wolfSSL"): + if int(group) in [25]: + if not (tls.startswith("OpenSSL") and ("build=OpenSSL 1.0.2" in tls or "build=OpenSSL 1.1" in tls or "build=OpenSSL 3.0" in tls) and ("run=OpenSSL 1.0.2" in tls or "run=OpenSSL 1.1" in tls or "run=OpenSSL 3.0" in tls)): + raise HwsimSkip("EC group not supported") +--- a/tests/hwsim/test_pmksa_cache.py ++++ b/tests/hwsim/test_pmksa_cache.py +@@ -955,7 +955,7 @@ def test_pmksa_cache_preauth_wpas_oom(de + eap_connect(dev[0], hapd, "PAX", "pax.user@example.com", + password_hex="0123456789abcdef0123456789abcdef", + bssid=apdev[0]['bssid']) +- for i in range(1, 11): ++ for i in range(1, 10): + with alloc_fail(dev[0], i, "rsn_preauth_init"): + res = dev[0].request("PREAUTH f2:11:22:33:44:55").strip() + logger.info("Iteration %d - PREAUTH command results: %s" % (i, res)) +@@ -963,7 +963,7 @@ def test_pmksa_cache_preauth_wpas_oom(de + state = dev[0].request('GET_ALLOC_FAIL') + if state.startswith('0:'): + break +- time.sleep(0.05) ++ time.sleep(0.10) + + def test_pmksa_cache_ctrl(dev, apdev): + """PMKSA cache control interface operations""" +--- a/tests/hwsim/test_sae.py ++++ b/tests/hwsim/test_sae.py +@@ -177,6 +177,11 @@ def test_sae_groups(dev, apdev): + if tls.startswith("OpenSSL") and "run=OpenSSL 1." in tls: + logger.info("Add Brainpool EC groups since OpenSSL is new enough") + sae_groups += [27, 28, 29, 30] ++ if tls.startswith("mbed TLS"): ++ # secp224k1 and secp224r1 (26) have prime p = 1 mod 4, and mbedtls ++ # does not have code to derive y from compressed format for those curves ++ sae_groups = [19, 25, 20, 21, 1, 2, 5, 14, 15, 16, 22, 23, 24] ++ sae_groups += [27, 28, 29, 30] + heavy_groups = [14, 15, 16] + suitable_groups = [15, 16, 17, 18, 19, 20, 21] + groups = [str(g) for g in sae_groups] +@@ -2193,6 +2198,8 @@ def run_sae_pwe_group(dev, apdev, group) + logger.info("Add Brainpool EC groups since OpenSSL is new enough") + elif tls.startswith("wolfSSL"): + logger.info("Make sure Brainpool EC groups were enabled when compiling wolfSSL") ++ elif tls.startswith("mbed TLS"): ++ logger.info("Make sure Brainpool EC groups were enabled when compiling mbed TLS") + else: + raise HwsimSkip("Brainpool curve not supported") + start_sae_pwe_ap(apdev[0], group, 2) +--- a/tests/hwsim/test_suite_b.py ++++ b/tests/hwsim/test_suite_b.py +@@ -27,6 +27,8 @@ def check_suite_b_tls_lib(dev, dhe=False + return + if tls.startswith("wolfSSL"): + return ++ if tls.startswith("mbed TLS"): ++ return + if not tls.startswith("OpenSSL"): + raise HwsimSkip("TLS library not supported for Suite B: " + tls) + supported = False +@@ -520,6 +522,7 @@ def test_suite_b_192_rsa_insufficient_dh + + dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192", + ieee80211w="2", ++ openssl_ciphers="DHE-RSA-AES256-GCM-SHA384", + phase1="tls_suiteb=1", + eap="TLS", identity="tls user", + ca_cert="auth_serv/rsa3072-ca.pem", +--- a/tests/hwsim/test_wpas_ctrl.py ++++ b/tests/hwsim/test_wpas_ctrl.py +@@ -1842,7 +1842,7 @@ def _test_wpas_ctrl_oom(dev): + tls = dev[0].request("GET tls_library") + if not tls.startswith("internal"): + tests.append(('NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG', 'FAIL', +- 4, 'wpas_ctrl_nfc_get_handover_sel_p2p')) ++ 3, 'wpas_ctrl_nfc_get_handover_sel_p2p')) + for cmd, exp, count, func in tests: + with alloc_fail(dev[0], count, func): + res = dev[0].request(cmd) +--- a/tests/hwsim/utils.py ++++ b/tests/hwsim/utils.py +@@ -141,7 +141,13 @@ def check_imsi_privacy_support(dev): + + def check_tls_tod(dev): + tls = dev.request("GET tls_library") +- if not tls.startswith("OpenSSL") and not tls.startswith("internal"): ++ if tls.startswith("OpenSSL"): ++ return ++ elif tls.startswith("internal"): ++ return ++ elif tls.startswith("mbed TLS"): ++ return ++ else: + raise HwsimSkip("TLS TOD-TOFU/STRICT not supported with this TLS library: " + tls) + + def vht_supported(): +--- /dev/null ++++ b/tests/test-crypto_module.c +@@ -0,0 +1,16 @@ ++/* ++ * crypto module tests - test program ++ * Copyright (c) 2022, Glenn Strauss <gstrauss@gluelogic.com> ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++#include "utils/module_tests.h" ++#include "crypto/crypto_module_tests.c" ++ ++int main(int argc, char *argv[]) ++{ ++ return crypto_module_tests(); ++} +--- a/tests/test-https.c ++++ b/tests/test-https.c +@@ -75,7 +75,7 @@ static int https_client(int s, const cha + struct tls_connection *conn; + struct wpabuf *in, *out, *appl; + int res = -1; +- int need_more_data; ++ int need_more_data = 0; + + os_memset(&conf, 0, sizeof(conf)); + conf.event_cb = https_tls_event_cb; +@@ -93,8 +93,12 @@ static int https_client(int s, const cha + + for (;;) { + appl = NULL; ++#ifdef CONFIG_TLS_INTERNAL_SERVER + out = tls_connection_handshake2(tls, conn, in, &appl, + &need_more_data); ++#else ++ out = tls_connection_handshake(tls, conn, in, &appl); ++#endif + wpabuf_free(in); + in = NULL; + if (out == NULL) { +@@ -152,11 +156,15 @@ static int https_client(int s, const cha + + wpa_printf(MSG_INFO, "Reading HTTP response"); + for (;;) { +- int need_more_data; ++ int need_more_data = 0; + in = https_recv(s); + if (in == NULL) + goto done; ++#ifdef CONFIG_TLS_INTERNAL_SERVER + out = tls_connection_decrypt2(tls, conn, in, &need_more_data); ++#else ++ out = tls_connection_decrypt(tls, conn, in); ++#endif + if (need_more_data) + wpa_printf(MSG_DEBUG, "HTTP: Need more data"); + wpabuf_free(in); +--- a/tests/test-https_server.c ++++ b/tests/test-https_server.c +@@ -67,10 +67,12 @@ static struct wpabuf * https_recv(int s, + } + + ++#ifdef CONFIG_TLS_INTERNAL_SERVER + static void https_tls_log_cb(void *ctx, const char *msg) + { + wpa_printf(MSG_DEBUG, "TLS: %s", msg); + } ++#endif + + + static int https_server(int s) +@@ -79,7 +81,7 @@ static int https_server(int s) + void *tls; + struct tls_connection_params params; + struct tls_connection *conn; +- struct wpabuf *in, *out, *appl; ++ struct wpabuf *in = NULL, *out = NULL, *appl = NULL; + int res = -1; + + os_memset(&conf, 0, sizeof(conf)); +@@ -106,7 +108,9 @@ static int https_server(int s) + return -1; + } + ++#ifdef CONFIG_TLS_INTERNAL_SERVER + tls_connection_set_log_cb(conn, https_tls_log_cb, NULL); ++#endif + + for (;;) { + in = https_recv(s, 5000); +@@ -147,12 +151,16 @@ static int https_server(int s) + + wpa_printf(MSG_INFO, "Reading HTTP request"); + for (;;) { +- int need_more_data; ++ int need_more_data = 0; + + in = https_recv(s, 5000); + if (!in) + goto done; ++#ifdef CONFIG_TLS_INTERNAL_SERVER + out = tls_connection_decrypt2(tls, conn, in, &need_more_data); ++#else ++ out = tls_connection_decrypt(tls, conn, in); ++#endif + wpabuf_free(in); + in = NULL; + if (need_more_data) { +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -1122,6 +1122,7 @@ CFLAGS += -DCONFIG_TLSV12 + endif + + ifeq ($(CONFIG_TLS), wolfssl) ++CFLAGS += -DCONFIG_TLS_WOLFSSL + ifdef TLS_FUNCS + CFLAGS += -DWOLFSSL_DER_LOAD + OBJS += ../src/crypto/tls_wolfssl.o +@@ -1137,6 +1138,7 @@ LIBS_p += -lwolfssl -lm + endif + + ifeq ($(CONFIG_TLS), openssl) ++CFLAGS += -DCONFIG_TLS_OPENSSL + CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 + ifdef TLS_FUNCS + CFLAGS += -DEAP_TLS_OPENSSL +@@ -1164,6 +1166,7 @@ CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONF + endif + + ifeq ($(CONFIG_TLS), mbedtls) ++CFLAGS += -DCONFIG_TLS_MBEDTLS + ifndef CONFIG_CRYPTO + CONFIG_CRYPTO=mbedtls + endif +@@ -1183,6 +1186,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), gnutls) ++CFLAGS += -DCONFIG_TLS_GNUTLS + ifndef CONFIG_CRYPTO + # default to libgcrypt + CONFIG_CRYPTO=gnutls +@@ -1213,6 +1217,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), internal) ++CFLAGS += -DCONFIG_TLS_INTERNAL + ifndef CONFIG_CRYPTO + CONFIG_CRYPTO=internal + endif +@@ -1293,6 +1298,7 @@ endif + endif + + ifeq ($(CONFIG_TLS), linux) ++CFLAGS += -DCONFIG_TLS_INTERNAL + OBJS += ../src/crypto/crypto_linux.o + OBJS_p += ../src/crypto/crypto_linux.o + ifdef TLS_FUNCS diff --git a/package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch b/package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch new file mode 100644 index 00000000000..c8c3ff33f42 --- /dev/null +++ b/package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch @@ -0,0 +1,45 @@ +From 33afce36c54b0cad38643629ded10ff5d727f077 Mon Sep 17 00:00:00 2001 +From: Glenn Strauss <gstrauss@gluelogic.com> +Date: Fri, 12 Aug 2022 05:34:47 -0400 +Subject: [PATCH 5/7] add NULL checks (encountered during tests/hwsim) + +sae_derive_commit_element_ecc NULL pwe_ecc check +dpp_gen_keypair() NULL curve check + +Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> +--- + src/common/dpp_crypto.c | 6 ++++++ + src/common/sae.c | 7 +++++++ + 2 files changed, 13 insertions(+) + +--- a/src/common/dpp_crypto.c ++++ b/src/common/dpp_crypto.c +@@ -269,6 +269,12 @@ int dpp_get_pubkey_hash(struct crypto_ec + + struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve) + { ++ if (curve == NULL) { ++ wpa_printf(MSG_DEBUG, ++ "DPP: %s curve must be initialized", __func__); ++ return NULL; ++ } ++ + struct crypto_ec_key *key; + + wpa_printf(MSG_DEBUG, "DPP: Generating a keypair"); +--- a/src/common/sae.c ++++ b/src/common/sae.c +@@ -1278,6 +1278,13 @@ void sae_deinit_pt(struct sae_pt *pt) + static int sae_derive_commit_element_ecc(struct sae_data *sae, + struct crypto_bignum *mask) + { ++ if (sae->tmp->pwe_ecc == NULL) { ++ wpa_printf(MSG_DEBUG, ++ "SAE: %s sae->tmp->pwe_ecc must be initialized", ++ __func__); ++ return -1; ++ } ++ + /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ + if (!sae->tmp->own_commit_element_ecc) { + sae->tmp->own_commit_element_ecc = diff --git a/package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch b/package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch new file mode 100644 index 00000000000..db4fcfe2357 --- /dev/null +++ b/package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch @@ -0,0 +1,26 @@ +From 54211caa2e0e5163aefef390daf88a971367a702 Mon Sep 17 00:00:00 2001 +From: Glenn Strauss <gstrauss@gluelogic.com> +Date: Tue, 4 Oct 2022 17:09:24 -0400 +Subject: [PATCH 6/7] dpp_pkex: EC point mul w/ value < prime + +crypto_ec_point_mul() with mbedtls requires point +be multiplied by a multiplicand with value < prime + +Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> +--- + src/common/dpp_crypto.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/src/common/dpp_crypto.c ++++ b/src/common/dpp_crypto.c +@@ -1588,7 +1588,9 @@ dpp_pkex_derive_Qr(const struct dpp_curv + Pr = crypto_ec_key_get_public_key(Pr_key); + Qr = crypto_ec_point_init(ec); + hash_bn = crypto_bignum_init_set(hash, curve->hash_len); +- if (!Pr || !Qr || !hash_bn || crypto_ec_point_mul(ec, Pr, hash_bn, Qr)) ++ if (!Pr || !Qr || !hash_bn || ++ crypto_bignum_mod(hash_bn, crypto_ec_get_prime(ec), hash_bn) || ++ crypto_ec_point_mul(ec, Pr, hash_bn, Qr)) + goto fail; + + if (crypto_ec_point_is_at_infinity(ec, Qr)) { diff --git a/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch b/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch new file mode 100644 index 00000000000..b0151b071f6 --- /dev/null +++ b/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch @@ -0,0 +1,141 @@ +From d4c4ef302f98fd6bce173b8636e7e350d8b44981 Mon Sep 17 00:00:00 2001 +From: P Praneesh <ppranees@codeaurora.org> +Date: Fri, 19 Mar 2021 12:17:27 +0530 +Subject: [PATCH] hostapd: update cfs0 and cfs1 for 160MHz + +As per standard Draft P802.11ax_D8.0,( Table 26-9—Setting +of the VHT Channel Width and VHT NSS at an HE STA +transmitting the OM Control subfield ), center frequency of +160MHz should be published in HT information subset 2 of +HT information when EXT NSS BW field is enabled. + +If the supported number of NSS in 160MHz is at least max NSS +support, then center_freq_seg0 indicates the center frequency of 80MHz and +center_freq_seg1 indicates the center frequency of 160MHz. + +If the supported number of NSS in 160MHz is less than max NSS +support, then center_freq_seg0 indicates the center frequency of 80MHz and +center_freq_seg1 is 0. The center frequency of 160MHz is published in HT +operation information element instead. + +Signed-off-by: P Praneesh <ppranees@codeaurora.org> +--- + hostapd/config_file.c | 2 ++ + src/ap/ieee802_11_ht.c | 7 +++++++ + src/ap/ieee802_11_vht.c | 16 ++++++++++++++++ + src/common/hw_features_common.c | 1 + + src/common/ieee802_11_defs.h | 1 + + 5 files changed, 27 insertions(+) + +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -1153,6 +1153,8 @@ static int hostapd_config_vht_capab(stru + conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN; + if (os_strstr(capab, "[TX-ANTENNA-PATTERN]")) + conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN; ++ if (os_strstr(capab, "[EXT-NSS-BW-SUPP]")) ++ conf->vht_capab |= VHT_CAP_EXTENDED_NSS_BW_SUPPORT; + return 0; + } + #endif /* CONFIG_IEEE80211AC */ +--- a/src/ap/ieee802_11_ht.c ++++ b/src/ap/ieee802_11_ht.c +@@ -82,7 +82,9 @@ u8 * hostapd_eid_ht_capabilities(struct + u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) + { + struct ieee80211_ht_operation *oper; ++ le32 vht_capabilities_info; + u8 *pos = eid; ++ u8 chwidth; + + if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n || + is_6ghz_op_class(hapd->iconf->op_class)) +@@ -103,6 +105,13 @@ u8 * hostapd_eid_ht_operation(struct hos + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | + HT_INFO_HT_PARAM_STA_CHNL_WIDTH; + ++ vht_capabilities_info = host_to_le32(hapd->iface->current_mode->vht_capab); ++ chwidth = hostapd_get_oper_chwidth(hapd->iconf); ++ if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT ++ && ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) { ++ oper->operation_mode = host_to_le16(hapd->iconf->vht_oper_centr_freq_seg0_idx << 5); ++ } ++ + pos += sizeof(*oper); + + return pos; +--- a/src/ap/ieee802_11_vht.c ++++ b/src/ap/ieee802_11_vht.c +@@ -25,6 +25,7 @@ u8 * hostapd_eid_vht_capabilities(struct + struct ieee80211_vht_capabilities *cap; + struct hostapd_hw_modes *mode = hapd->iface->current_mode; + u8 *pos = eid; ++ u8 chwidth; + + if (!mode || is_6ghz_op_class(hapd->iconf->op_class)) + return eid; +@@ -62,6 +63,17 @@ u8 * hostapd_eid_vht_capabilities(struct + host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET); + } + ++ chwidth = hostapd_get_oper_chwidth(hapd->iconf); ++ if (((host_to_le32(mode->vht_capab)) & VHT_CAP_EXTENDED_NSS_BW_SUPPORT) ++ && ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) { ++ cap->vht_capabilities_info |= VHT_CAP_EXTENDED_NSS_BW_SUPPORT; ++ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)); ++ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)); ++ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_MASK)); ++ } else { ++ cap->vht_capabilities_info &= ~VHT_CAP_EXTENDED_NSS_BW_SUPPORT_MASK; ++ } ++ + /* Supported MCS set comes from hw */ + os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8); + +@@ -74,6 +86,7 @@ u8 * hostapd_eid_vht_capabilities(struct + u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) + { + struct ieee80211_vht_operation *oper; ++ le32 vht_capabilities_info; + u8 *pos = eid; + enum oper_chan_width oper_chwidth = + hostapd_get_oper_chwidth(hapd->iconf); +@@ -106,6 +119,7 @@ u8 * hostapd_eid_vht_operation(struct ho + oper->vht_op_info_chan_center_freq_seg1_idx = seg1; + + oper->vht_op_info_chwidth = oper_chwidth; ++ vht_capabilities_info = host_to_le32(hapd->iface->current_mode->vht_capab); + if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) { + /* + * Convert 160 MHz channel width to new style as interop +@@ -119,6 +133,9 @@ u8 * hostapd_eid_vht_operation(struct ho + oper->vht_op_info_chan_center_freq_seg0_idx -= 8; + else + oper->vht_op_info_chan_center_freq_seg0_idx += 8; ++ ++ if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT) ++ oper->vht_op_info_chan_center_freq_seg1_idx = 0; + } else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) { + /* + * Convert 80+80 MHz channel width to new style as interop +--- a/src/common/hw_features_common.c ++++ b/src/common/hw_features_common.c +@@ -811,6 +811,7 @@ int ieee80211ac_cap_check(u32 hw, u32 co + VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); + VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); + VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); ++ VHT_CAP_CHECK(VHT_CAP_EXTENDED_NSS_BW_SUPPORT); + + #undef VHT_CAP_CHECK + #undef VHT_CAP_CHECK_MAX +--- a/src/common/ieee802_11_defs.h ++++ b/src/common/ieee802_11_defs.h +@@ -1349,6 +1349,8 @@ struct ieee80211_ampe_ie { + #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27)) + #define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28)) + #define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29)) ++#define VHT_CAP_EXTENDED_NSS_BW_SUPPORT ((u32) BIT(30)) ++#define VHT_CAP_EXTENDED_NSS_BW_SUPPORT_MASK ((u32) BIT(30) | BIT(31)) + + #define VHT_OPMODE_CHANNEL_WIDTH_MASK ((u8) BIT(0) | BIT(1)) + #define VHT_OPMODE_CHANNEL_RxNSS_MASK ((u8) BIT(4) | BIT(5) | \ diff --git a/package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch b/package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch new file mode 100644 index 00000000000..4929c581ce2 --- /dev/null +++ b/package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Thu, 14 Sep 2023 10:53:50 +0200 +Subject: [PATCH] driver_nl80211: fix setting QoS map on secondary BSSs + +The setting is per-BSS, not per PHY + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -11341,7 +11341,7 @@ static int nl80211_set_qos_map(void *pri + wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map", + qos_map_set, qos_map_set_len); + +- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) || ++ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_QOS_MAP)) || + nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) { + nlmsg_free(msg); + return -ENOBUFS; diff --git a/package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch b/package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch new file mode 100644 index 00000000000..adfb21fb471 --- /dev/null +++ b/package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch @@ -0,0 +1,18 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Thu, 14 Sep 2023 11:28:03 +0200 +Subject: [PATCH] driver_nl80211: update drv->ifindex on removing the first + BSS + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -8867,6 +8867,7 @@ static int wpa_driver_nl80211_if_remove( + if (drv->first_bss->next) { + drv->first_bss = drv->first_bss->next; + drv->ctx = drv->first_bss->ctx; ++ drv->ifindex = drv->first_bss->ifindex; + os_free(bss); + } else { + wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to"); diff --git a/package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch b/package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch new file mode 100644 index 00000000000..395c6459542 --- /dev/null +++ b/package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch @@ -0,0 +1,34 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Mon, 18 Sep 2023 16:47:41 +0200 +Subject: [PATCH] nl80211: move nl80211_put_freq_params call outside of + 802.11ax #ifdef + +The relevance of this call is not specific to 802.11ax, so it should be done +even with CONFIG_IEEE80211AX disabled. + +Fixes: b3921db426ea ("nl80211: Add frequency info in start AP command") +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -5226,6 +5226,9 @@ static int wpa_driver_nl80211_set_ap(voi + nla_nest_end(msg, ftm); + } + ++ if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0) ++ goto fail; ++ + #ifdef CONFIG_IEEE80211AX + if (params->he_spr_ctrl) { + struct nlattr *spr; +@@ -5260,9 +5263,6 @@ static int wpa_driver_nl80211_set_ap(voi + nla_nest_end(msg, spr); + } + +- if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0) +- goto fail; +- + if (params->freq && params->freq->he_enabled) { + struct nlattr *bss_color; + diff --git a/package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch b/package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch new file mode 100644 index 00000000000..fe81318385f --- /dev/null +++ b/package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch @@ -0,0 +1,28 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 20 Sep 2023 13:41:10 +0200 +Subject: [PATCH] hostapd: cancel channel_list_update_timeout in + hostapd_cleanup_iface_partial + +Fixes a crash when disabling an interface during channel list update + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -569,6 +569,7 @@ static void sta_track_deinit(struct host + void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) + { + wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); ++ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); + #ifdef NEED_AP_MLME + hostapd_stop_setup_timers(iface); + #endif /* NEED_AP_MLME */ +@@ -598,7 +599,6 @@ void hostapd_cleanup_iface_partial(struc + static void hostapd_cleanup_iface(struct hostapd_iface *iface) + { + wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); +- eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); + eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, + NULL); + diff --git a/package/network/services/hostapd/patches/200-multicall.patch b/package/network/services/hostapd/patches/200-multicall.patch index 8dce2608719..e3ed00f2ded 100644 --- a/package/network/services/hostapd/patches/200-multicall.patch +++ b/package/network/services/hostapd/patches/200-multicall.patch @@ -18,7 +18,7 @@ OBJS += ../src/ap/vlan_init.o OBJS += ../src/ap/vlan_ifconfig.o OBJS += ../src/ap/vlan.o -@@ -349,10 +351,14 @@ CFLAGS += -DCONFIG_MBO +@@ -357,10 +359,14 @@ CFLAGS += -DCONFIG_MBO OBJS += ../src/ap/mbo_ap.o endif @@ -36,7 +36,7 @@ LIBS += $(DRV_AP_LIBS) ifdef CONFIG_L2_PACKET -@@ -1277,6 +1283,12 @@ install: $(addprefix $(DESTDIR)$(BINDIR) +@@ -1380,6 +1386,12 @@ install: $(addprefix $(DESTDIR)$(BINDIR) _OBJS_VAR := OBJS include ../src/objs.mk @@ -49,7 +49,7 @@ hostapd: $(OBJS) $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS) @$(E) " LD " $@ -@@ -1351,6 +1363,12 @@ include ../src/objs.mk +@@ -1460,6 +1472,12 @@ include ../src/objs.mk _OBJS_VAR := SOBJS include ../src/objs.mk @@ -64,15 +64,15 @@ @$(E) " LD " $@ --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile -@@ -17,6 +17,7 @@ endif +@@ -10,6 +10,7 @@ ALL += dbus/fi.w1.wpa_supplicant1.servic EXTRA_TARGETS=dynamic_eap_methods CONFIG_FILE=.config +-include $(if $(MULTICALL),../hostapd/.config) include ../src/build.rules - ifdef LIBS -@@ -359,7 +360,9 @@ endif + ifdef CONFIG_BUILD_PASN_SO +@@ -382,7 +383,9 @@ endif ifdef CONFIG_IBSS_RSN NEED_RSN_AUTHENTICATOR=y CFLAGS += -DCONFIG_IBSS_RSN @@ -82,7 +82,7 @@ OBJS += ibss_rsn.o endif -@@ -897,6 +900,10 @@ ifdef CONFIG_DYNAMIC_EAP_METHODS +@@ -924,6 +927,10 @@ ifdef CONFIG_DYNAMIC_EAP_METHODS CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS LIBS += -ldl -rdynamic endif @@ -93,7 +93,7 @@ endif ifdef CONFIG_AP -@@ -904,9 +911,11 @@ NEED_EAP_COMMON=y +@@ -931,9 +938,11 @@ NEED_EAP_COMMON=y NEED_RSN_AUTHENTICATOR=y CFLAGS += -DCONFIG_AP OBJS += ap.o @@ -105,7 +105,7 @@ OBJS += ../src/ap/hostapd.o OBJS += ../src/ap/wpa_auth_glue.o OBJS += ../src/ap/utils.o -@@ -986,6 +995,12 @@ endif +@@ -1022,6 +1031,12 @@ endif ifdef CONFIG_HS20 OBJS += ../src/ap/hs20.o endif @@ -118,7 +118,7 @@ endif ifdef CONFIG_MBO -@@ -994,7 +1009,9 @@ CFLAGS += -DCONFIG_MBO +@@ -1030,7 +1045,9 @@ CFLAGS += -DCONFIG_MBO endif ifdef NEED_RSN_AUTHENTICATOR @@ -128,7 +128,7 @@ NEED_AES_WRAP=y OBJS += ../src/ap/wpa_auth.o OBJS += ../src/ap/wpa_auth_ie.o -@@ -1889,6 +1906,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv) +@@ -2010,6 +2027,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv) _OBJS_VAR := OBJS include ../src/objs.mk @@ -141,7 +141,7 @@ wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs) $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) @$(E) " LD " $@ -@@ -2021,6 +2044,12 @@ eap_gpsk.so: $(SRC_EAP_GPSK) +@@ -2142,6 +2165,12 @@ eap_gpsk.so: $(SRC_EAP_GPSK) $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ @$(E) " sed" $< @@ -156,7 +156,7 @@ wpa_cli.exe: wpa_cli --- a/src/drivers/driver.h +++ b/src/drivers/driver.h -@@ -6025,8 +6025,8 @@ union wpa_event_data { +@@ -6667,8 +6667,8 @@ union wpa_event_data { * Driver wrapper code should call this function whenever an event is received * from the driver. */ @@ -167,7 +167,7 @@ /** * wpa_supplicant_event_global - Report a driver event for wpa_supplicant -@@ -6038,7 +6038,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -6680,7 +6680,7 @@ void wpa_supplicant_event(void *ctx, enu * Same as wpa_supplicant_event(), but we search for the interface in * wpa_global. */ @@ -178,7 +178,7 @@ /* --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c -@@ -1836,8 +1836,8 @@ err: +@@ -2184,8 +2184,8 @@ err: #endif /* CONFIG_OWE */ @@ -189,7 +189,7 @@ { struct hostapd_data *hapd = ctx; #ifndef CONFIG_NO_STDOUT_DEBUG -@@ -2082,7 +2082,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -2489,7 +2489,7 @@ void wpa_supplicant_event(void *ctx, enu } @@ -200,7 +200,7 @@ struct hapd_interfaces *interfaces = ctx; --- a/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant/wpa_priv.c -@@ -1038,8 +1038,8 @@ static void wpa_priv_send_ft_response(st +@@ -1039,8 +1039,8 @@ static void wpa_priv_send_ft_response(st } @@ -211,7 +211,7 @@ { struct wpa_priv_interface *iface = ctx; -@@ -1102,7 +1102,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -1103,7 +1103,7 @@ void wpa_supplicant_event(void *ctx, enu } @@ -220,7 +220,7 @@ union wpa_event_data *data) { struct wpa_priv_global *global = ctx; -@@ -1215,6 +1215,8 @@ int main(int argc, char *argv[]) +@@ -1217,6 +1217,8 @@ int main(int argc, char *argv[]) if (os_program_init()) return -1; @@ -231,7 +231,7 @@ os_memset(&global, 0, sizeof(global)); --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c -@@ -4665,8 +4665,8 @@ static void wpas_event_unprot_beacon(str +@@ -5353,8 +5353,8 @@ static void wpas_link_reconfig(struct wp } @@ -242,7 +242,7 @@ { struct wpa_supplicant *wpa_s = ctx; int resched; -@@ -5511,7 +5511,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -6272,7 +6272,7 @@ void wpa_supplicant_event(void *ctx, enu } @@ -253,7 +253,7 @@ struct wpa_supplicant *wpa_s; --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -6819,7 +6819,6 @@ struct wpa_interface * wpa_supplicant_ma +@@ -7462,7 +7462,6 @@ struct wpa_interface * wpa_supplicant_ma return NULL; } @@ -261,7 +261,7 @@ /** * wpa_supplicant_match_existing - Match existing interfaces * @global: Pointer to global data from wpa_supplicant_init() -@@ -6854,6 +6853,11 @@ static int wpa_supplicant_match_existing +@@ -7497,6 +7496,11 @@ static int wpa_supplicant_match_existing #endif /* CONFIG_MATCH_IFACE */ @@ -273,7 +273,7 @@ /** * wpa_supplicant_add_iface - Add a new network interface -@@ -7110,6 +7114,8 @@ struct wpa_global * wpa_supplicant_init( +@@ -7753,6 +7757,8 @@ struct wpa_global * wpa_supplicant_init( #ifndef CONFIG_NO_WPA_MSG wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb); #endif /* CONFIG_NO_WPA_MSG */ @@ -284,7 +284,7 @@ wpa_debug_open_file(params->wpa_debug_file_path); --- a/hostapd/main.c +++ b/hostapd/main.c -@@ -590,6 +590,11 @@ fail: +@@ -698,6 +698,11 @@ fail: return -1; } @@ -296,14 +296,14 @@ #ifdef CONFIG_WPS static int gen_uuid(const char *txt_addr) -@@ -683,6 +688,8 @@ int main(int argc, char *argv[]) +@@ -791,6 +796,8 @@ int main(int argc, char *argv[]) return -1; #endif /* CONFIG_DPP */ + wpa_supplicant_event = hostapd_wpa_event; + wpa_supplicant_event_global = hostapd_wpa_event_global; for (;;) { - c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:"); + c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q"); if (c < 0) --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -320,7 +320,7 @@ { --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c -@@ -30,7 +30,12 @@ +@@ -31,7 +31,12 @@ #include "ctrl_iface.h" #include "pcsc_funcs.h" #include "wpas_glue.h" @@ -333,7 +333,7 @@ const struct wpa_driver_ops *const wpa_drivers[] = { NULL }; -@@ -1291,6 +1296,10 @@ static void usage(void) +@@ -1303,6 +1308,10 @@ static void usage(void) "option several times.\n"); } @@ -344,7 +344,7 @@ int main(int argc, char *argv[]) { -@@ -1311,6 +1320,8 @@ int main(int argc, char *argv[]) +@@ -1323,6 +1332,8 @@ int main(int argc, char *argv[]) if (os_program_init()) return -1; diff --git a/package/network/services/hostapd/patches/300-noscan.patch b/package/network/services/hostapd/patches/300-noscan.patch index 93b09342838..3b5f4325de0 100644 --- a/package/network/services/hostapd/patches/300-noscan.patch +++ b/package/network/services/hostapd/patches/300-noscan.patch @@ -1,6 +1,6 @@ --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -3459,6 +3459,10 @@ static int hostapd_config_fill(struct ho +@@ -3448,6 +3448,10 @@ static int hostapd_config_fill(struct ho if (bss->ocv && !bss->ieee80211w) bss->ieee80211w = 1; #endif /* CONFIG_OCV */ @@ -13,7 +13,7 @@ } else if (os_strcmp(buf, "ht_capab") == 0) { --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -1009,6 +1009,8 @@ struct hostapd_config { +@@ -1075,6 +1075,8 @@ struct hostapd_config { int ht_op_mode_fixed; u16 ht_capab; @@ -24,7 +24,7 @@ int no_pri_sec_switch; --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c -@@ -517,7 +517,8 @@ static int ieee80211n_check_40mhz(struct +@@ -546,7 +546,8 @@ static int ieee80211n_check_40mhz(struct int ret; /* Check that HT40 is used and PRI / SEC switch is allowed */ @@ -36,7 +36,7 @@ hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c -@@ -230,6 +230,9 @@ void hostapd_2040_coex_action(struct hos +@@ -239,6 +239,9 @@ void hostapd_2040_coex_action(struct hos return; } @@ -46,7 +46,7 @@ if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) { wpa_printf(MSG_DEBUG, "Ignore too short 20/40 BSS Coexistence Management frame"); -@@ -390,6 +393,9 @@ void ht40_intolerant_add(struct hostapd_ +@@ -399,6 +402,9 @@ void ht40_intolerant_add(struct hostapd_ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) return; diff --git a/package/network/services/hostapd/patches/301-mesh-noscan.patch b/package/network/services/hostapd/patches/301-mesh-noscan.patch index 0d783294419..ceb6d0c161f 100644 --- a/package/network/services/hostapd/patches/301-mesh-noscan.patch +++ b/package/network/services/hostapd/patches/301-mesh-noscan.patch @@ -1,6 +1,6 @@ --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c -@@ -2532,6 +2532,7 @@ static const struct parse_data ssid_fiel +@@ -2600,6 +2600,7 @@ static const struct parse_data ssid_fiel #else /* CONFIG_MESH */ { INT_RANGE(mode, 0, 4) }, #endif /* CONFIG_MESH */ @@ -10,7 +10,7 @@ { STR(id_str) }, --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c -@@ -768,6 +768,7 @@ static void wpa_config_write_network(FIL +@@ -775,6 +775,7 @@ static void wpa_config_write_network(FIL #endif /* IEEE8021X_EAPOL */ INT(mode); INT(no_auto_peer); @@ -20,44 +20,56 @@ INT(enable_edmg); --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c -@@ -474,6 +474,8 @@ static int wpa_supplicant_mesh_init(stru +@@ -506,6 +506,8 @@ static int wpa_supplicant_mesh_init(stru frequency); goto out_free; } -+ if (ssid->noscan) -+ conf->noscan = 1; ++ if (conf->noscan) ++ ssid->noscan = 1; if (ssid->mesh_basic_rates == NULL) { /* --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -2384,12 +2384,12 @@ void ibss_mesh_setup_freq(struct wpa_sup +@@ -2710,7 +2710,7 @@ static bool ibss_mesh_can_use_vht(struct + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode) + { +- if (mode->mode != HOSTAPD_MODE_IEEE80211A) ++ if (mode->mode != HOSTAPD_MODE_IEEE80211A && !(ssid->noscan)) + return false; + + if (!drv_supports_vht(wpa_s, ssid)) +@@ -2783,7 +2783,7 @@ static void ibss_mesh_select_40mhz(struc + int i, res; + unsigned int j; + static const int ht40plus[] = { +- 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 165, 173, ++ 1, 2, 3, 4, 5, 6, 7, 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 165, 173, + 184, 192 + }; + int ht40 = -1; +@@ -3033,7 +3033,7 @@ void ibss_mesh_setup_freq(struct wpa_sup int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode); enum hostapd_hw_mode hw_mode; struct hostapd_hw_modes *mode = NULL; -- int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, -+ int ht40plus[] = { 1, 2, 3, 4, 5, 6, 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, - 184, 192 }; - int vht80[] = { 36, 52, 100, 116, 132, 149 }; - struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; +- int i, obss_scan = 1; ++ int i, obss_scan = !(ssid->noscan); u8 channel; -- int i, chan_idx, ht40 = -1, res, obss_scan = 1; -+ int i, chan_idx, ht40 = -1, res, obss_scan = !(ssid->noscan); - unsigned int j, k; - struct hostapd_freq_params vht_freq; - int chwidth, seg0, seg1; -@@ -2473,7 +2473,7 @@ void ibss_mesh_setup_freq(struct wpa_sup - #endif /* CONFIG_HE_OVERRIDES */ - + bool is_6ghz; + bool dfs_enabled = wpa_s->conf->country[0] && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_RADAR); +@@ -3080,6 +3080,8 @@ void ibss_mesh_setup_freq(struct wpa_sup + freq->he_enabled = ibss_mesh_can_use_he(wpa_s, ssid, mode, + ieee80211_mode); + freq->channel = channel; ++ if (mode->mode == HOSTAPD_MODE_IEEE80211G && ssid->noscan) ++ ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan, dfs_enabled); /* Setup higher BW only for 5 GHz */ -- if (mode->mode != HOSTAPD_MODE_IEEE80211A) -+ if (mode->mode != HOSTAPD_MODE_IEEE80211A && !(ssid->noscan)) - return; - - for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) { + if (mode->mode == HOSTAPD_MODE_IEEE80211A) { + ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan, dfs_enabled); --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h -@@ -971,6 +971,8 @@ struct wpa_ssid { +@@ -1035,6 +1035,8 @@ struct wpa_ssid { */ int no_auto_peer; diff --git a/package/network/services/hostapd/patches/310-rescan_immediately.patch b/package/network/services/hostapd/patches/310-rescan_immediately.patch index 7f5e2070696..6e0244bca29 100644 --- a/package/network/services/hostapd/patches/310-rescan_immediately.patch +++ b/package/network/services/hostapd/patches/310-rescan_immediately.patch @@ -1,6 +1,6 @@ --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -5154,7 +5154,7 @@ wpa_supplicant_alloc(struct wpa_supplica +@@ -5769,7 +5769,7 @@ wpa_supplicant_alloc(struct wpa_supplica if (wpa_s == NULL) return NULL; wpa_s->scan_req = INITIAL_SCAN_REQ; diff --git a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch index 9ced08801ee..c11c9572169 100644 --- a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch +++ b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch @@ -1,8 +1,8 @@ --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -4973,7 +4973,7 @@ static int nl80211_set_channel(struct i8 - freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled, - freq->bandwidth, freq->center_freq1, freq->center_freq2); +@@ -5407,7 +5407,7 @@ static int nl80211_set_channel(struct i8 + freq->he_enabled, freq->eht_enabled, freq->bandwidth, + freq->center_freq1, freq->center_freq2); - msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL : + msg = nl80211_bss_msg(bss, 0, set_chan ? NL80211_CMD_SET_CHANNEL : diff --git a/package/network/services/hostapd/patches/340-reload_freq_change.patch b/package/network/services/hostapd/patches/340-reload_freq_change.patch deleted file mode 100644 index 3d51a47a1ed..00000000000 --- a/package/network/services/hostapd/patches/340-reload_freq_change.patch +++ /dev/null @@ -1,75 +0,0 @@ ---- a/src/ap/hostapd.c -+++ b/src/ap/hostapd.c -@@ -115,6 +115,28 @@ static void hostapd_reload_bss(struct ho - #endif /* CONFIG_NO_RADIUS */ - - ssid = &hapd->conf->ssid; -+ -+ hostapd_set_freq(hapd, hapd->iconf->hw_mode, hapd->iface->freq, -+ hapd->iconf->channel, -+ hapd->iconf->enable_edmg, -+ hapd->iconf->edmg_channel, -+ hapd->iconf->ieee80211n, -+ hapd->iconf->ieee80211ac, -+ hapd->iconf->ieee80211ax, -+ hapd->iconf->secondary_channel, -+ hostapd_get_oper_chwidth(hapd->iconf), -+ hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf), -+ hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf)); -+ -+ if (hapd->iface->current_mode) { -+ if (hostapd_prepare_rates(hapd->iface, hapd->iface->current_mode)) { -+ wpa_printf(MSG_ERROR, "Failed to prepare rates table."); -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_WARNING, -+ "Failed to prepare rates table."); -+ } -+ } -+ - if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next && - ssid->wpa_passphrase_set && ssid->wpa_passphrase) { - /* -@@ -216,6 +238,7 @@ int hostapd_reload_config(struct hostapd - struct hostapd_data *hapd = iface->bss[0]; - struct hostapd_config *newconf, *oldconf; - size_t j; -+ int i; - - if (iface->config_fname == NULL) { - /* Only in-memory config in use - assume it has been updated */ -@@ -266,24 +289,20 @@ int hostapd_reload_config(struct hostapd - } - iface->conf = newconf; - -+ for (i = 0; i < iface->num_hw_features; i++) { -+ struct hostapd_hw_modes *mode = &iface->hw_features[i]; -+ if (mode->mode == iface->conf->hw_mode) { -+ iface->current_mode = mode; -+ break; -+ } -+ } -+ -+ if (iface->conf->channel) -+ iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel); -+ - for (j = 0; j < iface->num_bss; j++) { - hapd = iface->bss[j]; - hapd->iconf = newconf; -- hapd->iconf->channel = oldconf->channel; -- hapd->iconf->acs = oldconf->acs; -- hapd->iconf->secondary_channel = oldconf->secondary_channel; -- hapd->iconf->ieee80211n = oldconf->ieee80211n; -- hapd->iconf->ieee80211ac = oldconf->ieee80211ac; -- hapd->iconf->ht_capab = oldconf->ht_capab; -- hapd->iconf->vht_capab = oldconf->vht_capab; -- hostapd_set_oper_chwidth(hapd->iconf, -- hostapd_get_oper_chwidth(oldconf)); -- hostapd_set_oper_centr_freq_seg0_idx( -- hapd->iconf, -- hostapd_get_oper_centr_freq_seg0_idx(oldconf)); -- hostapd_set_oper_centr_freq_seg1_idx( -- hapd->iconf, -- hostapd_get_oper_centr_freq_seg1_idx(oldconf)); - hapd->conf = newconf->bss[j]; - hostapd_reload_bss(hapd); - } diff --git a/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch b/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch index 73f81f65e6f..8784452876b 100644 --- a/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch +++ b/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch @@ -1,6 +1,6 @@ --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c -@@ -1513,15 +1513,35 @@ int ap_switch_channel(struct wpa_supplic +@@ -1825,15 +1825,35 @@ int ap_switch_channel(struct wpa_supplic #ifdef CONFIG_CTRL_IFACE diff --git a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch index 1f9b74e97ee..647ca2cbf97 100644 --- a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch +++ b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch @@ -1,54 +1,35 @@ --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -2918,10 +2918,15 @@ static int wpa_driver_nl80211_del_beacon - struct nl_msg *msg; - struct wpa_driver_nl80211_data *drv = bss->drv; +@@ -3008,12 +3008,12 @@ static int wpa_driver_nl80211_del_beacon + return 0; -+ if (!bss->beacon_set) -+ return 0; -+ -+ bss->beacon_set = 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)", - drv->ifindex); + bss->ifindex); + link->beacon_set = 0; + link->freq = 0; + nl80211_put_wiphy_data_ap(bss); - msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON); + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_BEACON); - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); - } + if (!msg) + return -ENOBUFS; -@@ -5602,7 +5607,7 @@ static void nl80211_teardown_ap(struct i +@@ -6100,7 +6100,7 @@ static void nl80211_teardown_ap(struct i nl80211_mgmt_unsubscribe(bss, "AP teardown"); nl80211_put_wiphy_data_ap(bss); -- bss->beacon_set = 0; -+ wpa_driver_nl80211_del_beacon(bss); +- bss->flink->beacon_set = 0; ++ wpa_driver_nl80211_del_beacon_all(bss); } -@@ -8051,8 +8056,6 @@ static int wpa_driver_nl80211_if_remove( +@@ -8859,8 +8859,6 @@ static int wpa_driver_nl80211_if_remove( } else { wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context"); nl80211_teardown_ap(bss); - if (!bss->added_if && !drv->first_bss->next) -- wpa_driver_nl80211_del_beacon(bss); +- wpa_driver_nl80211_del_beacon_all(bss); nl80211_destroy_bss(bss); if (!bss->added_if) i802_set_iface_flags(bss, 0); -@@ -8449,7 +8452,6 @@ static int wpa_driver_nl80211_deinit_ap( - if (!is_ap_interface(drv->nlmode)) - return -1; - wpa_driver_nl80211_del_beacon(bss); -- bss->beacon_set = 0; - - /* - * If the P2P GO interface was dynamically added, then it is -@@ -8469,7 +8471,6 @@ static int wpa_driver_nl80211_stop_ap(vo - if (!is_ap_interface(drv->nlmode)) - return -1; - wpa_driver_nl80211_del_beacon(bss); -- bss->beacon_set = 0; - return 0; - } - diff --git a/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch b/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch deleted file mode 100644 index 349522e06a1..00000000000 --- a/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch +++ /dev/null @@ -1,106 +0,0 @@ ---- a/hostapd/ctrl_iface.c -+++ b/hostapd/ctrl_iface.c -@@ -67,6 +67,7 @@ - #include "fst/fst_ctrl_iface.h" - #include "config_file.h" - #include "ctrl_iface.h" -+#include "config_file.h" - - - #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256 -@@ -82,6 +83,7 @@ static void hostapd_ctrl_iface_send(stru - enum wpa_msg_type type, - const char *buf, size_t len); - -+static char *reload_opts = NULL; - - static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, - struct sockaddr_storage *from, -@@ -133,6 +135,61 @@ static int hostapd_ctrl_iface_new_sta(st - return 0; - } - -+static char *get_option(char *opt, char *str) -+{ -+ int len = strlen(str); -+ -+ if (!strncmp(opt, str, len)) -+ return opt + len; -+ else -+ return NULL; -+} -+ -+static struct hostapd_config *hostapd_ctrl_iface_config_read(const char *fname) -+{ -+ struct hostapd_config *conf; -+ char *opt, *val; -+ -+ conf = hostapd_config_read(fname); -+ if (!conf) -+ return NULL; -+ -+ for (opt = strtok(reload_opts, " "); -+ opt; -+ opt = strtok(NULL, " ")) { -+ -+ if ((val = get_option(opt, "channel="))) -+ conf->channel = atoi(val); -+ else if ((val = get_option(opt, "ht_capab="))) -+ conf->ht_capab = atoi(val); -+ else if ((val = get_option(opt, "ht_capab_mask="))) -+ conf->ht_capab &= atoi(val); -+ else if ((val = get_option(opt, "sec_chan="))) -+ conf->secondary_channel = atoi(val); -+ else if ((val = get_option(opt, "hw_mode="))) -+ conf->hw_mode = atoi(val); -+ else if ((val = get_option(opt, "ieee80211n="))) -+ conf->ieee80211n = atoi(val); -+ else -+ break; -+ } -+ -+ return conf; -+} -+ -+static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt) -+{ -+ struct hostapd_config * (*config_read_cb)(const char *config_fname); -+ struct hostapd_iface *iface = hapd->iface; -+ -+ config_read_cb = iface->interfaces->config_read_cb; -+ iface->interfaces->config_read_cb = hostapd_ctrl_iface_config_read; -+ reload_opts = txt; -+ -+ hostapd_reload_config(iface); -+ -+ iface->interfaces->config_read_cb = config_read_cb; -+} - - #ifdef NEED_AP_MLME - static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, -@@ -3754,6 +3811,8 @@ static int hostapd_ctrl_iface_receive_pr - } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { - reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply, - reply_size); -+ } else if (os_strncmp(buf, "UPDATE ", 7) == 0) { -+ hostapd_ctrl_iface_update(hapd, buf + 7); - } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { - ieee802_1x_erp_flush(hapd); - #ifdef RADIUS_SERVER ---- a/src/ap/ctrl_iface_ap.c -+++ b/src/ap/ctrl_iface_ap.c -@@ -919,7 +919,13 @@ int hostapd_parse_csa_settings(const cha - - int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd) - { -- return hostapd_drv_stop_ap(hapd); -+ struct hostapd_iface *iface = hapd->iface; -+ int i; -+ -+ for (i = 0; i < iface->num_bss; i++) -+ hostapd_drv_stop_ap(iface->bss[i]); -+ -+ return 0; - } - - diff --git a/package/network/services/hostapd/patches/370-ap_sta_support.patch b/package/network/services/hostapd/patches/370-ap_sta_support.patch deleted file mode 100644 index c5cad3bb8da..00000000000 --- a/package/network/services/hostapd/patches/370-ap_sta_support.patch +++ /dev/null @@ -1,392 +0,0 @@ ---- a/wpa_supplicant/Makefile -+++ b/wpa_supplicant/Makefile -@@ -108,6 +108,8 @@ OBJS_c += ../src/utils/common.o - OBJS_c += ../src/common/cli.o - OBJS += wmm_ac.o - -+OBJS += ../src/common/wpa_ctrl.o -+ - ifndef CONFIG_OS - ifdef CONFIG_NATIVE_WINDOWS - CONFIG_OS=win32 ---- a/wpa_supplicant/bss.c -+++ b/wpa_supplicant/bss.c -@@ -11,6 +11,7 @@ - #include "utils/common.h" - #include "utils/eloop.h" - #include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" - #include "drivers/driver.h" - #include "eap_peer/eap.h" - #include "wpa_supplicant_i.h" -@@ -282,6 +283,10 @@ void calculate_update_time(const struct - static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, - struct os_reltime *fetch_time) - { -+ struct ieee80211_ht_capabilities *capab; -+ struct ieee80211_ht_operation *oper; -+ struct ieee802_11_elems elems; -+ - dst->flags = src->flags; - os_memcpy(dst->bssid, src->bssid, ETH_ALEN); - dst->freq = src->freq; -@@ -294,6 +299,15 @@ static void wpa_bss_copy_res(struct wpa_ - dst->est_throughput = src->est_throughput; - dst->snr = src->snr; - -+ memset(&elems, 0, sizeof(elems)); -+ ieee802_11_parse_elems((u8 *) (src + 1), src->ie_len, &elems, 0); -+ capab = (struct ieee80211_ht_capabilities *) elems.ht_capabilities; -+ oper = (struct ieee80211_ht_operation *) elems.ht_operation; -+ if (capab) -+ dst->ht_capab = le_to_host16(capab->ht_capabilities_info); -+ if (oper) -+ dst->ht_param = oper->ht_param; -+ - calculate_update_time(fetch_time, src->age, &dst->last_update); - } - ---- a/wpa_supplicant/bss.h -+++ b/wpa_supplicant/bss.h -@@ -94,6 +94,10 @@ struct wpa_bss { - u8 ssid[SSID_MAX_LEN]; - /** Length of SSID */ - size_t ssid_len; -+ /** HT capabilities */ -+ u16 ht_capab; -+ /* Five octets of HT Operation Information */ -+ u8 ht_param; - /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */ - int freq; - /** Beacon interval in TUs (host byte order) */ ---- a/wpa_supplicant/main.c -+++ b/wpa_supplicant/main.c -@@ -34,7 +34,7 @@ static void usage(void) - "vW] [-P<pid file>] " - "[-g<global ctrl>] \\\n" - " [-G<group>] \\\n" -- " -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] " -+ " -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-H<hostapd path>] " - "[-p<driver_param>] \\\n" - " [-b<br_ifname>] [-e<entropy file>]" - #ifdef CONFIG_DEBUG_FILE -@@ -74,6 +74,7 @@ static void usage(void) - " -g = global ctrl_interface\n" - " -G = global ctrl_interface group\n" - " -h = show this help text\n" -+ " -H = connect to a hostapd instance to manage state changes\n" - " -i = interface name\n" - " -I = additional configuration file\n" - " -K = include keys (passwords, etc.) in debug output\n" -@@ -201,7 +202,7 @@ int main(int argc, char *argv[]) - - for (;;) { - c = getopt(argc, argv, -- "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW"); -+ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuvW"); - if (c < 0) - break; - switch (c) { -@@ -248,6 +249,9 @@ int main(int argc, char *argv[]) - usage(); - exitcode = 0; - goto out; -+ case 'H': -+ iface->hostapd_ctrl = optarg; -+ break; - case 'i': - iface->ifname = optarg; - break; ---- a/wpa_supplicant/wpa_supplicant.c -+++ b/wpa_supplicant/wpa_supplicant.c -@@ -130,6 +130,54 @@ static void wpas_update_fils_connect_par - static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s); - #endif /* CONFIG_OWE */ - -+static int hostapd_stop(struct wpa_supplicant *wpa_s) -+{ -+ const char *cmd = "STOP_AP"; -+ char buf[256]; -+ size_t len = sizeof(buf); -+ -+ if (wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL) < 0) { -+ wpa_printf(MSG_ERROR, "\nFailed to stop hostapd AP interfaces\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+static int hostapd_reload(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) -+{ -+ char *cmd = NULL; -+ char buf[256]; -+ size_t len = sizeof(buf); -+ enum hostapd_hw_mode hw_mode; -+ u8 channel; -+ int sec_chan = 0; -+ int ret; -+ -+ if (!bss) -+ return -1; -+ -+ if (bss->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { -+ int sec = bss->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; -+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) -+ sec_chan = 1; -+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) -+ sec_chan = -1; -+ } -+ -+ hw_mode = ieee80211_freq_to_chan(bss->freq, &channel); -+ if (asprintf(&cmd, "UPDATE channel=%d sec_chan=%d hw_mode=%d", -+ channel, sec_chan, hw_mode) < 0) -+ return -1; -+ -+ ret = wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL); -+ free(cmd); -+ -+ if (ret < 0) { -+ wpa_printf(MSG_ERROR, "\nFailed to reload hostapd AP interfaces\n"); -+ return -1; -+ } -+ return 0; -+} - - #ifdef CONFIG_WEP - /* Configure default/group WEP keys for static WEP */ -@@ -1007,6 +1055,8 @@ void wpa_supplicant_set_state(struct wpa - - sme_sched_obss_scan(wpa_s, 1); - -+ if (wpa_s->hostapd) -+ hostapd_reload(wpa_s, wpa_s->current_bss); - #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) - if (!fils_hlp_sent && ssid && ssid->eap.erp) - update_fils_connect_params = true; -@@ -1017,6 +1067,8 @@ void wpa_supplicant_set_state(struct wpa - #endif /* CONFIG_OWE */ - } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING || - state == WPA_ASSOCIATED) { -+ if (wpa_s->hostapd) -+ hostapd_stop(wpa_s); - wpa_s->new_connection = 1; - wpa_drv_set_operstate(wpa_s, 0); - #ifndef IEEE8021X_EAPOL -@@ -2276,6 +2328,8 @@ void wpa_supplicant_associate(struct wpa - return; - } - wpa_s->current_bss = bss; -+ if (wpa_s->hostapd) -+ hostapd_reload(wpa_s, wpa_s->current_bss); - #else /* CONFIG_MESH */ - wpa_msg(wpa_s, MSG_ERROR, - "mesh mode support not included in the build"); -@@ -6426,6 +6480,16 @@ static int wpa_supplicant_init_iface(str - sizeof(wpa_s->bridge_ifname)); - } - -+ if (iface->hostapd_ctrl) { -+ wpa_s->hostapd = wpa_ctrl_open(iface->hostapd_ctrl); -+ if (!wpa_s->hostapd) { -+ wpa_printf(MSG_ERROR, "\nFailed to connect to hostapd\n"); -+ return -1; -+ } -+ if (hostapd_stop(wpa_s) < 0) -+ return -1; -+ } -+ - /* RSNA Supplicant Key Management - INITIALIZE */ - eapol_sm_notify_portEnabled(wpa_s->eapol, false); - eapol_sm_notify_portValid(wpa_s->eapol, false); -@@ -6763,6 +6827,11 @@ static void wpa_supplicant_deinit_iface( - if (terminate) - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING); - -+ if (wpa_s->hostapd) { -+ wpa_ctrl_close(wpa_s->hostapd); -+ wpa_s->hostapd = NULL; -+ } -+ - wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface); - wpa_s->ctrl_iface = NULL; - ---- a/wpa_supplicant/wpa_supplicant_i.h -+++ b/wpa_supplicant/wpa_supplicant_i.h -@@ -103,6 +103,11 @@ struct wpa_interface { - const char *ifname; - - /** -+ * hostapd_ctrl - path to hostapd control socket for notification -+ */ -+ const char *hostapd_ctrl; -+ -+ /** - * bridge_ifname - Optional bridge interface name - * - * If the driver interface (ifname) is included in a Linux bridge -@@ -615,6 +620,8 @@ struct wpa_supplicant { - #endif /* CONFIG_CTRL_IFACE_BINDER */ - char bridge_ifname[16]; - -+ struct wpa_ctrl *hostapd; -+ - char *confname; - char *confanother; - ---- a/hostapd/ctrl_iface.c -+++ b/hostapd/ctrl_iface.c -@@ -2883,6 +2883,11 @@ static int hostapd_ctrl_iface_chan_switc - return 0; - } - -+ if (os_strstr(pos, " auto-ht")) { -+ settings.freq_params.ht_enabled = iface->conf->ieee80211n; -+ settings.freq_params.vht_enabled = iface->conf->ieee80211ac; -+ } -+ - for (i = 0; i < iface->num_bss; i++) { - - /* Save CHAN_SWITCH VHT and HE config */ ---- a/src/ap/beacon.c -+++ b/src/ap/beacon.c -@@ -1758,11 +1758,6 @@ int ieee802_11_set_beacon(struct hostapd - return -1; - } - -- if (hapd->csa_in_progress) { -- wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); -- return -1; -- } -- - hapd->beacon_set_done = 1; - - if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) ---- a/wpa_supplicant/events.c -+++ b/wpa_supplicant/events.c -@@ -4665,6 +4665,60 @@ static void wpas_event_unprot_beacon(str - } - - -+static void -+supplicant_ch_switch_started(struct wpa_supplicant *wpa_s, -+ union wpa_event_data *data) -+{ -+ char buf[256]; -+ size_t len = sizeof(buf); -+ char *cmd = NULL; -+ int width = 20; -+ int ret; -+ -+ if (!wpa_s->hostapd) -+ return; -+ -+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH -+ "count=%d freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d", -+ data->ch_switch.count, -+ data->ch_switch.freq, -+ data->ch_switch.ht_enabled, -+ data->ch_switch.ch_offset, -+ channel_width_to_string(data->ch_switch.ch_width), -+ data->ch_switch.cf1, -+ data->ch_switch.cf2); -+ -+ switch (data->ch_switch.ch_width) { -+ case CHAN_WIDTH_20_NOHT: -+ case CHAN_WIDTH_20: -+ width = 20; -+ break; -+ case CHAN_WIDTH_40: -+ width = 40; -+ break; -+ case CHAN_WIDTH_80: -+ width = 80; -+ break; -+ case CHAN_WIDTH_160: -+ case CHAN_WIDTH_80P80: -+ width = 160; -+ break; -+ } -+ -+ asprintf(&cmd, "CHAN_SWITCH %d %d sec_channel_offset=%d center_freq1=%d center_freq2=%d, bandwidth=%d auto-ht\n", -+ data->ch_switch.count - 1, -+ data->ch_switch.freq, -+ data->ch_switch.ch_offset, -+ data->ch_switch.cf1, -+ data->ch_switch.cf2, -+ width); -+ ret = wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL); -+ free(cmd); -+ -+ if (ret < 0) -+ wpa_printf(MSG_ERROR, "\nFailed to reload hostapd AP interfaces\n"); -+} -+ - void supplicant_event(void *ctx, enum wpa_event_type event, - union wpa_event_data *data) - { -@@ -4980,8 +5034,10 @@ void supplicant_event(void *ctx, enum wp - channel_width_to_string(data->ch_switch.ch_width), - data->ch_switch.cf1, - data->ch_switch.cf2); -- if (event == EVENT_CH_SWITCH_STARTED) -+ if (event == EVENT_CH_SWITCH_STARTED) { -+ supplicant_ch_switch_started(wpa_s, data); - break; -+ } - - wpa_s->assoc_freq = data->ch_switch.freq; - wpa_s->current_ssid->frequency = data->ch_switch.freq; ---- a/src/drivers/driver.h -+++ b/src/drivers/driver.h -@@ -5829,6 +5829,7 @@ union wpa_event_data { - - /** - * struct ch_switch -+ * @count: Count until channel switch activates - * @freq: Frequency of new channel in MHz - * @ht_enabled: Whether this is an HT channel - * @ch_offset: Secondary channel offset -@@ -5837,6 +5838,7 @@ union wpa_event_data { - * @cf2: Center frequency 2 - */ - struct ch_switch { -+ int count; - int freq; - int ht_enabled; - int ch_offset; ---- a/src/drivers/driver_nl80211_event.c -+++ b/src/drivers/driver_nl80211_event.c -@@ -684,7 +684,7 @@ static void mlme_event_ch_switch(struct - struct nlattr *ifindex, struct nlattr *freq, - struct nlattr *type, struct nlattr *bw, - struct nlattr *cf1, struct nlattr *cf2, -- int finished) -+ struct nlattr *count, int finished) - { - struct i802_bss *bss; - union wpa_event_data data; -@@ -745,6 +745,8 @@ static void mlme_event_ch_switch(struct - data.ch_switch.cf1 = nla_get_u32(cf1); - if (cf2) - data.ch_switch.cf2 = nla_get_u32(cf2); -+ if (count) -+ data.ch_switch.count = nla_get_u32(count); - - if (finished) - bss->freq = data.ch_switch.freq; -@@ -3003,6 +3005,7 @@ static void do_process_drv_event(struct - tb[NL80211_ATTR_CHANNEL_WIDTH], - tb[NL80211_ATTR_CENTER_FREQ1], - tb[NL80211_ATTR_CENTER_FREQ2], -+ tb[NL80211_ATTR_CH_SWITCH_COUNT], - 0); - break; - case NL80211_CMD_CH_SWITCH_NOTIFY: -@@ -3013,6 +3016,7 @@ static void do_process_drv_event(struct - tb[NL80211_ATTR_CHANNEL_WIDTH], - tb[NL80211_ATTR_CENTER_FREQ1], - tb[NL80211_ATTR_CENTER_FREQ2], -+ NULL, - 1); - break; - case NL80211_CMD_DISCONNECT: diff --git a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch index ca634077b72..f7720fce2fa 100644 --- a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch +++ b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch @@ -12,7 +12,7 @@ else --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c -@@ -3569,6 +3569,7 @@ static int hostapd_ctrl_iface_receive_pr +@@ -3314,6 +3314,7 @@ static int hostapd_ctrl_iface_receive_pr reply_size); } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) { reply_len = hostapd_drv_status(hapd, reply, reply_size); @@ -20,7 +20,7 @@ } else if (os_strcmp(buf, "MIB") == 0) { reply_len = ieee802_11_get_mib(hapd, reply, reply_size); if (reply_len >= 0) { -@@ -3610,6 +3611,7 @@ static int hostapd_ctrl_iface_receive_pr +@@ -3355,6 +3356,7 @@ static int hostapd_ctrl_iface_receive_pr } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, reply_size); @@ -30,7 +30,7 @@ reply_len = -1; --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile -@@ -955,6 +955,9 @@ ifdef CONFIG_FILS +@@ -983,6 +983,9 @@ ifdef CONFIG_FILS OBJS += ../src/ap/fils_hlp.o endif ifdef CONFIG_CTRL_IFACE @@ -42,7 +42,7 @@ --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c -@@ -2308,7 +2308,7 @@ static int wpa_supplicant_ctrl_iface_sta +@@ -2326,7 +2326,7 @@ static int wpa_supplicant_ctrl_iface_sta pos += ret; } @@ -51,7 +51,7 @@ if (wpa_s->ap_iface) { pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos, end - pos, -@@ -10919,6 +10919,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12087,6 +12087,7 @@ char * wpa_supplicant_ctrl_iface_process reply_len = -1; } else if (os_strncmp(buf, "NOTE ", 5) == 0) { wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); @@ -59,7 +59,7 @@ } else if (os_strcmp(buf, "MIB") == 0) { reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); if (reply_len >= 0) { -@@ -10931,6 +10932,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12099,6 +12100,7 @@ char * wpa_supplicant_ctrl_iface_process reply_size - reply_len); #endif /* CONFIG_MACSEC */ } @@ -67,7 +67,7 @@ } else if (os_strncmp(buf, "STATUS", 6) == 0) { reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); -@@ -11419,6 +11421,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12587,6 +12589,7 @@ char * wpa_supplicant_ctrl_iface_process reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); #ifdef CONFIG_AP @@ -75,7 +75,7 @@ } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "STA ", 4) == 0) { -@@ -11427,12 +11430,15 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12595,12 +12598,15 @@ char * wpa_supplicant_ctrl_iface_process } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, reply_size); @@ -93,15 +93,61 @@ reply_len = -1; --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c -@@ -25,6 +25,7 @@ - #include "mbo_ap.h" +@@ -26,6 +26,26 @@ #include "taxonomy.h" - + #include "wnm_ap.h" + ++static const char * hw_mode_str(enum hostapd_hw_mode mode) ++{ ++ switch (mode) { ++ case HOSTAPD_MODE_IEEE80211B: ++ return "b"; ++ case HOSTAPD_MODE_IEEE80211G: ++ return "g"; ++ case HOSTAPD_MODE_IEEE80211A: ++ return "a"; ++ case HOSTAPD_MODE_IEEE80211AD: ++ return "ad"; ++ case HOSTAPD_MODE_IEEE80211ANY: ++ return "any"; ++ case NUM_HOSTAPD_MODES: ++ return "invalid"; ++ } ++ return "unknown"; ++} ++ +#ifdef CONFIG_CTRL_IFACE_MIB static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen, size_t curr_len, const u8 *mcs_set) -@@ -451,6 +452,7 @@ int hostapd_ctrl_iface_sta_next(struct h +@@ -212,26 +232,6 @@ static const char * timeout_next_str(int + } + + +-static const char * hw_mode_str(enum hostapd_hw_mode mode) +-{ +- switch (mode) { +- case HOSTAPD_MODE_IEEE80211B: +- return "b"; +- case HOSTAPD_MODE_IEEE80211G: +- return "g"; +- case HOSTAPD_MODE_IEEE80211A: +- return "a"; +- case HOSTAPD_MODE_IEEE80211AD: +- return "ad"; +- case HOSTAPD_MODE_IEEE80211ANY: +- return "any"; +- case NUM_HOSTAPD_MODES: +- return "invalid"; +- } +- return "unknown"; +-} +- +- + static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, + struct sta_info *sta, + char *buf, size_t buflen) +@@ -493,6 +493,7 @@ int hostapd_ctrl_iface_sta_next(struct h return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); } @@ -109,7 +155,7 @@ #ifdef CONFIG_P2P_MANAGER static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, -@@ -807,12 +809,12 @@ int hostapd_ctrl_iface_status(struct hos +@@ -884,12 +885,12 @@ int hostapd_ctrl_iface_status(struct hos return len; len += ret; } @@ -126,7 +172,7 @@ if (os_snprintf_error(buflen - len, ret)) --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c -@@ -2712,6 +2712,7 @@ static const char * bool_txt(bool val) +@@ -2834,6 +2834,7 @@ static const char * bool_txt(bool val) return val ? "TRUE" : "FALSE"; } @@ -134,7 +180,7 @@ int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) { -@@ -2898,6 +2899,7 @@ int ieee802_1x_get_mib_sta(struct hostap +@@ -3020,6 +3021,7 @@ int ieee802_1x_get_mib_sta(struct hostap return len; } @@ -144,7 +190,7 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c -@@ -4519,6 +4519,7 @@ static const char * wpa_bool_txt(int val +@@ -5328,6 +5328,7 @@ static const char * wpa_bool_txt(int val return val ? "TRUE" : "FALSE"; } @@ -152,7 +198,7 @@ #define RSN_SUITE "%02x-%02x-%02x-%d" #define RSN_SUITE_ARG(s) \ -@@ -4669,7 +4670,7 @@ int wpa_get_mib_sta(struct wpa_state_mac +@@ -5480,7 +5481,7 @@ int wpa_get_mib_sta(struct wpa_state_mac return len; } @@ -163,7 +209,7 @@ { --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c -@@ -2767,6 +2767,8 @@ static u32 wpa_key_mgmt_suite(struct wpa +@@ -3834,6 +3834,8 @@ static u32 wpa_key_mgmt_suite(struct wpa } @@ -172,7 +218,7 @@ #define RSN_SUITE "%02x-%02x-%02x-%d" #define RSN_SUITE_ARG(s) \ ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff -@@ -2848,6 +2850,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch +@@ -3915,6 +3917,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch return (int) len; } @@ -182,7 +228,7 @@ --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c -@@ -1364,7 +1364,7 @@ int wpas_ap_wps_nfc_report_handover(stru +@@ -1499,7 +1499,7 @@ int wpas_ap_wps_nfc_report_handover(stru #endif /* CONFIG_WPS */ diff --git a/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch b/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch index d2414faf01f..e9083f6ecc6 100644 --- a/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch +++ b/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch @@ -1,6 +1,6 @@ --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c -@@ -744,7 +744,7 @@ static int wpa_ctrl_command_sta(struct w +@@ -757,7 +757,7 @@ static int wpa_ctrl_command_sta(struct w } buf[len] = '\0'; diff --git a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch index 65a8b07e65a..4592c341277 100644 --- a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch +++ b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch @@ -1,6 +1,6 @@ --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c -@@ -2444,6 +2444,31 @@ u32 wpa_akm_to_suite(int akm) +@@ -2841,6 +2841,31 @@ u32 wpa_akm_to_suite(int akm) } @@ -32,7 +32,7 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) -@@ -2451,8 +2476,19 @@ int wpa_compare_rsn_ie(int ft_initial_as +@@ -2848,8 +2873,19 @@ int wpa_compare_rsn_ie(int ft_initial_as if (ie1 == NULL || ie2 == NULL) return -1; diff --git a/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch b/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch index 73a8c7694d5..edcd9852574 100644 --- a/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch +++ b/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch @@ -11,7 +11,7 @@ bss->wpa_pairwise |= WPA_CIPHER_TKIP; #endif /* CONFIG_NO_TKIP */ bss->rsn_pairwise = bss->wpa_pairwise; -@@ -1178,8 +1177,7 @@ int hostapd_init_wps(struct hostapd_data +@@ -1181,8 +1180,7 @@ int hostapd_init_wps(struct hostapd_data WPA_CIPHER_GCMP_256)) { wps->encr_types |= WPS_ENCR_AES; wps->encr_types_rsn |= WPS_ENCR_AES; diff --git a/package/network/services/hostapd/patches/410-limit_debug_messages.patch b/package/network/services/hostapd/patches/410-limit_debug_messages.patch index d2713fc29b2..48a5589200f 100644 --- a/package/network/services/hostapd/patches/410-limit_debug_messages.patch +++ b/package/network/services/hostapd/patches/410-limit_debug_messages.patch @@ -60,7 +60,7 @@ #ifdef CONFIG_DEBUG_FILE static char *last_path = NULL; #endif /* CONFIG_DEBUG_FILE */ -@@ -636,7 +610,7 @@ void wpa_msg_register_ifname_cb(wpa_msg_ +@@ -644,7 +618,7 @@ void wpa_msg_register_ifname_cb(wpa_msg_ } @@ -69,7 +69,7 @@ { va_list ap; char *buf; -@@ -674,7 +648,7 @@ void wpa_msg(void *ctx, int level, const +@@ -682,7 +656,7 @@ void wpa_msg(void *ctx, int level, const } @@ -80,9 +80,9 @@ char *buf; --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h -@@ -50,6 +50,17 @@ int wpa_debug_reopen_file(void); - void wpa_debug_close_file(void); +@@ -51,6 +51,17 @@ void wpa_debug_close_file(void); void wpa_debug_setup_stdout(void); + void wpa_debug_stop_log(void); +/* internal */ +void _wpa_hexdump(int level, const char *title, const u8 *buf, @@ -98,7 +98,7 @@ /** * wpa_debug_printf_timestamp - Print timestamp for debug output * -@@ -70,9 +81,15 @@ void wpa_debug_print_timestamp(void); +@@ -71,9 +82,15 @@ void wpa_debug_print_timestamp(void); * * Note: New line '\n' is added to the end of the text when printing to stdout. */ @@ -115,7 +115,7 @@ /** * wpa_hexdump - conditional hex dump * @level: priority level (MSG_*) of the message -@@ -84,7 +101,13 @@ PRINTF_FORMAT(2, 3); +@@ -85,7 +102,13 @@ PRINTF_FORMAT(2, 3); * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump. */ @@ -130,7 +130,7 @@ static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) -@@ -106,7 +129,13 @@ static inline void wpa_hexdump_buf(int l +@@ -107,7 +130,13 @@ static inline void wpa_hexdump_buf(int l * like wpa_hexdump(), but by default, does not include secret keys (passwords, * etc.) in debug output. */ @@ -145,7 +145,7 @@ static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) -@@ -128,8 +157,14 @@ static inline void wpa_hexdump_buf_key(i +@@ -129,8 +158,14 @@ static inline void wpa_hexdump_buf_key(i * the hex numbers and ASCII characters (for printable range) are shown. 16 * bytes per line will be shown. */ @@ -162,7 +162,7 @@ /** * wpa_hexdump_ascii_key - conditional hex dump, hide keys -@@ -145,8 +180,14 @@ void wpa_hexdump_ascii(int level, const +@@ -146,8 +181,14 @@ void wpa_hexdump_ascii(int level, const * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by * default, does not include secret keys (passwords, etc.) in debug output. */ @@ -179,7 +179,7 @@ /* * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce -@@ -183,7 +224,12 @@ void wpa_hexdump_ascii_key(int level, co +@@ -184,7 +225,12 @@ void wpa_hexdump_ascii_key(int level, co * * Note: New line '\n' is added to the end of the text when printing to stdout. */ @@ -193,7 +193,7 @@ /** * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors -@@ -197,8 +243,13 @@ void wpa_msg(void *ctx, int level, const +@@ -198,8 +244,13 @@ void wpa_msg(void *ctx, int level, const * attached ctrl_iface monitors. In other words, it can be used for frequent * events that do not need to be sent to syslog. */ diff --git a/package/network/services/hostapd/patches/420-indicate-features.patch b/package/network/services/hostapd/patches/420-indicate-features.patch index f9dff66073c..07df8e5a9af 100644 --- a/package/network/services/hostapd/patches/420-indicate-features.patch +++ b/package/network/services/hostapd/patches/420-indicate-features.patch @@ -1,23 +1,24 @@ --- a/hostapd/main.c +++ b/hostapd/main.c -@@ -15,6 +15,7 @@ - #include "utils/common.h" - #include "utils/eloop.h" - #include "utils/uuid.h" -+#include "utils/build_features.h" - #include "crypto/random.h" - #include "crypto/tls.h" - #include "common/version.h" -@@ -691,7 +692,7 @@ int main(int argc, char *argv[]) +@@ -31,7 +31,7 @@ + #include "config_file.h" + #include "eap_register.h" + #include "ctrl_iface.h" +- ++#include "build_features.h" + + struct hapd_global { + void **drv_priv; +@@ -799,7 +799,7 @@ int main(int argc, char *argv[]) wpa_supplicant_event = hostapd_wpa_event; wpa_supplicant_event_global = hostapd_wpa_event_global; for (;;) { -- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:"); -+ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:v::"); +- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q"); ++ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:qv::"); if (c < 0) break; switch (c) { -@@ -728,6 +729,8 @@ int main(int argc, char *argv[]) +@@ -836,6 +836,8 @@ int main(int argc, char *argv[]) break; #endif /* CONFIG_DEBUG_LINUX_TRACING */ case 'v': @@ -25,7 +26,7 @@ + exit(!has_feature(optarg)); show_version(); exit(1); - break; + case 'g': --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -12,6 +12,7 @@ @@ -33,19 +34,19 @@ #include "common.h" +#include "build_features.h" + #include "crypto/crypto.h" #include "fst/fst.h" #include "wpa_supplicant_i.h" - #include "driver_i.h" @@ -202,7 +203,7 @@ int main(int argc, char *argv[]) for (;;) { c = getopt(argc, argv, -- "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuvW"); -+ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuv::W"); +- "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW"); ++ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuv::W"); if (c < 0) break; switch (c) { -@@ -305,8 +306,12 @@ int main(int argc, char *argv[]) +@@ -302,8 +303,12 @@ int main(int argc, char *argv[]) break; #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ case 'v': diff --git a/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch b/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch index dc1fa3d29d9..a21f0bf7cee 100644 --- a/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch +++ b/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch @@ -1,6 +1,6 @@ --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c -@@ -388,7 +388,6 @@ static int hostapd_cli_cmd_disassociate( +@@ -401,7 +401,6 @@ static int hostapd_cli_cmd_disassociate( } @@ -8,7 +8,7 @@ static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc, char *argv[]) { -@@ -401,7 +400,6 @@ static int hostapd_cli_cmd_signature(str +@@ -414,7 +413,6 @@ static int hostapd_cli_cmd_signature(str os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]); return wpa_ctrl_command(ctrl, buf); } @@ -16,7 +16,7 @@ static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, -@@ -418,7 +416,6 @@ static int hostapd_cli_cmd_sa_query(stru +@@ -431,7 +429,6 @@ static int hostapd_cli_cmd_sa_query(stru } @@ -24,7 +24,7 @@ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { -@@ -644,7 +641,6 @@ static int hostapd_cli_cmd_wps_config(st +@@ -657,7 +654,6 @@ static int hostapd_cli_cmd_wps_config(st ssid_hex, argv[1]); return wpa_ctrl_command(ctrl, buf); } @@ -32,7 +32,7 @@ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, -@@ -1579,13 +1575,10 @@ static const struct hostapd_cli_cmd host +@@ -1610,13 +1606,10 @@ static const struct hostapd_cli_cmd host { "disassociate", hostapd_cli_cmd_disassociate, hostapd_complete_stations, "<addr> = disassociate a station" }, @@ -46,7 +46,7 @@ { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, -@@ -1610,7 +1603,6 @@ static const struct hostapd_cli_cmd host +@@ -1641,7 +1634,6 @@ static const struct hostapd_cli_cmd host "<SSID> <auth> <encr> <key> = configure AP" }, { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, "= show current WPS status" }, diff --git a/package/network/services/hostapd/patches/432-missing-typedef.patch b/package/network/services/hostapd/patches/432-missing-typedef.patch deleted file mode 100644 index 7a100f1a0d2..00000000000 --- a/package/network/services/hostapd/patches/432-missing-typedef.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/src/drivers/linux_wext.h -+++ b/src/drivers/linux_wext.h -@@ -26,6 +26,7 @@ typedef int32_t __s32; - typedef uint16_t __u16; - typedef int16_t __s16; - typedef uint8_t __u8; -+typedef int8_t __s8; - #ifndef __user - #define __user - #endif /* __user */ diff --git a/package/network/services/hostapd/patches/450-scan_wait.patch b/package/network/services/hostapd/patches/450-scan_wait.patch deleted file mode 100644 index ac874ad66a4..00000000000 --- a/package/network/services/hostapd/patches/450-scan_wait.patch +++ /dev/null @@ -1,73 +0,0 @@ ---- a/hostapd/main.c -+++ b/hostapd/main.c -@@ -39,6 +39,8 @@ struct hapd_global { - }; - - static struct hapd_global global; -+static int daemonize = 0; -+static char *pid_file = NULL; - - - #ifndef CONFIG_NO_HOSTAPD_LOGGER -@@ -146,6 +148,14 @@ static void hostapd_logger_cb(void *ctx, - } - #endif /* CONFIG_NO_HOSTAPD_LOGGER */ - -+static void hostapd_setup_complete_cb(void *ctx) -+{ -+ if (daemonize && os_daemonize(pid_file)) { -+ perror("daemon"); -+ return; -+ } -+ daemonize = 0; -+} - - /** - * hostapd_driver_init - Preparate driver interface -@@ -164,6 +174,8 @@ static int hostapd_driver_init(struct ho - return -1; - } - -+ hapd->setup_complete_cb = hostapd_setup_complete_cb; -+ - /* Initialize the driver interface */ - if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) - b = NULL; -@@ -404,8 +416,6 @@ static void hostapd_global_deinit(const - #endif /* CONFIG_NATIVE_WINDOWS */ - - eap_server_unregister_methods(); -- -- os_daemonize_terminate(pid_file); - } - - -@@ -431,18 +441,6 @@ static int hostapd_global_run(struct hap - } - #endif /* EAP_SERVER_TNC */ - -- if (daemonize) { -- if (os_daemonize(pid_file)) { -- wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); -- return -1; -- } -- if (eloop_sock_requeue()) { -- wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s", -- strerror(errno)); -- return -1; -- } -- } -- - eloop_run(); - - return 0; -@@ -645,8 +643,7 @@ int main(int argc, char *argv[]) - struct hapd_interfaces interfaces; - int ret = 1; - size_t i, j; -- int c, debug = 0, daemonize = 0; -- char *pid_file = NULL; -+ int c, debug = 0; - const char *log_file = NULL; - const char *entropy_file = NULL; - char **bss_config = NULL, **tmp_bss; diff --git a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch index e0e687e1613..dc19553e26e 100644 --- a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch +++ b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch @@ -22,7 +22,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org> #include "common/defs.h" #include "common/ieee802_11_defs.h" #include "common/wpa_common.h" -@@ -851,6 +852,9 @@ struct wpa_driver_associate_params { +@@ -953,6 +954,9 @@ struct wpa_driver_associate_params { * responsible for selecting with which BSS to associate. */ const u8 *bssid; @@ -42,7 +42,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org> #include "config.h" -@@ -2321,6 +2322,97 @@ static char * wpa_config_write_peerkey(c +@@ -2389,6 +2390,97 @@ static char * wpa_config_write_mac_value #endif /* NO_CONFIG_WRITE */ @@ -140,7 +140,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org> /* Helper macros for network block parser */ #ifdef OFFSET -@@ -2606,6 +2698,8 @@ static const struct parse_data ssid_fiel +@@ -2674,6 +2766,8 @@ static const struct parse_data ssid_fiel { INT(ap_max_inactivity) }, { INT(dtim_period) }, { INT(beacon_int) }, @@ -162,7 +162,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org> #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1) -@@ -843,6 +845,9 @@ struct wpa_ssid { +@@ -879,6 +881,9 @@ struct wpa_ssid { */ void *parent_cred; @@ -174,7 +174,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org> * macsec_policy - Determines the policy for MACsec secure session --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -3726,6 +3726,12 @@ static void wpas_start_assoc_cb(struct w +@@ -4177,6 +4177,12 @@ static void wpas_start_assoc_cb(struct w params.beacon_int = ssid->beacon_int; else params.beacon_int = wpa_s->conf->beacon_int; diff --git a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch b/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch deleted file mode 100644 index 1d2a053faaf..00000000000 --- a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch +++ /dev/null @@ -1,59 +0,0 @@ -From ffc4445958a3ed4064f2e1bf73fa478a61c5cf7b Mon Sep 17 00:00:00 2001 -From: Antonio Quartulli <ordex@autistici.org> -Date: Sun, 3 Jun 2012 18:42:25 +0200 -Subject: [PATCHv2 602/602] driver_nl80211: use new parameters during ibss join - -Signed-hostap: Antonio Quartulli <ordex@autistici.org> ---- - src/drivers/driver_nl80211.c | 33 ++++++++++++++++++++++++++++++++- - 1 file changed, 32 insertions(+), 1 deletion(-) - ---- a/src/drivers/driver_nl80211.c -+++ b/src/drivers/driver_nl80211.c -@@ -5951,7 +5951,7 @@ static int wpa_driver_nl80211_ibss(struc - struct wpa_driver_associate_params *params) - { - struct nl_msg *msg; -- int ret = -1; -+ int ret = -1, i; - int count = 0; - - wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); -@@ -5978,6 +5978,37 @@ retry: - nl80211_put_beacon_int(msg, params->beacon_int)) - goto fail; - -+ if (params->fixed_freq) { -+ wpa_printf(MSG_DEBUG, " * fixed_freq"); -+ nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED); -+ } -+ -+ if (params->beacon_int > 0) { -+ wpa_printf(MSG_DEBUG, " * beacon_int=%d", -+ params->beacon_int); -+ nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL, -+ params->beacon_int); -+ } -+ -+ if (params->rates[0] > 0) { -+ wpa_printf(MSG_DEBUG, " * basic_rates:"); -+ i = 0; -+ while (i < NL80211_MAX_SUPP_RATES && -+ params->rates[i] > 0) { -+ wpa_printf(MSG_DEBUG, " %.1f", -+ (double)params->rates[i] / 2); -+ i++; -+ } -+ nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, i, -+ params->rates); -+ } -+ -+ if (params->mcast_rate > 0) { -+ wpa_printf(MSG_DEBUG, " * mcast_rate=%.1f", -+ (double)params->mcast_rate / 10); -+ nla_put_u32(msg, NL80211_ATTR_MCAST_RATE, params->mcast_rate); -+ } -+ - ret = nl80211_set_conn_keys(params, msg); - if (ret) - goto fail; diff --git a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch index 1794befe950..daa36c2f35c 100644 --- a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch +++ b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch @@ -19,7 +19,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com> --- a/src/drivers/driver.h +++ b/src/drivers/driver.h -@@ -1618,6 +1618,7 @@ struct wpa_driver_mesh_join_params { +@@ -1827,6 +1827,7 @@ struct wpa_driver_mesh_join_params { #define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008 unsigned int flags; bool handle_dfs; @@ -29,7 +29,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com> struct wpa_driver_set_key_params { --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -10476,6 +10476,18 @@ static int nl80211_put_mesh_id(struct nl +@@ -11667,6 +11667,18 @@ static int nl80211_put_mesh_id(struct nl } @@ -48,7 +48,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com> static int nl80211_put_mesh_config(struct nl_msg *msg, struct wpa_driver_mesh_bss_params *params) { -@@ -10537,6 +10549,7 @@ static int nl80211_join_mesh(struct i802 +@@ -11728,6 +11740,7 @@ static int nl80211_join_mesh(struct i802 nl80211_put_basic_rates(msg, params->basic_rates) || nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) || nl80211_put_beacon_int(msg, params->beacon_int) || @@ -58,7 +58,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com> --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c -@@ -600,6 +600,7 @@ int wpa_supplicant_join_mesh(struct wpa_ +@@ -632,6 +632,7 @@ int wpa_supplicant_join_mesh(struct wpa_ params->meshid = ssid->ssid; params->meshid_len = ssid->ssid_len; diff --git a/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch b/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch index 4c7cb9ea36f..4d7d85f4ab8 100644 --- a/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch +++ b/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch @@ -1,19 +1,13 @@ --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -2457,11 +2457,13 @@ void ibss_mesh_setup_freq(struct wpa_sup - for (j = 0; j < wpa_s->last_scan_res_used; j++) { - struct wpa_bss *bss = wpa_s->last_scan_res[j]; +@@ -3040,6 +3040,10 @@ void ibss_mesh_setup_freq(struct wpa_sup -- if (ssid->mode != WPAS_MODE_IBSS) -+ /* Don't adjust control freq in case of fixed_freq */ -+ if (ssid->fixed_freq) { -+ obss_scan = 0; - break; -+ } + freq->freq = ssid->frequency; -- /* Don't adjust control freq in case of fixed_freq */ -- if (ssid->fixed_freq) -+ if (ssid->mode != WPAS_MODE_IBSS) - break; ++ if (ssid->fixed_freq) { ++ obss_scan = 0; ++ } ++ + if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) { + struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid); - if (!bss_is_ibss(bss)) diff --git a/package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch b/package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch new file mode 100644 index 00000000000..7d3d94648e1 --- /dev/null +++ b/package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch @@ -0,0 +1,24 @@ +From c9304d3303d563ad6d2619f4e07864ed12f96889 Mon Sep 17 00:00:00 2001 +From: David Bauer <mail@david-bauer.net> +Date: Sat, 14 May 2022 21:41:03 +0200 +Subject: [PATCH] hostapd: config: support random BSS color + +Configure the HE BSS color to a random value in case the config defines +a BSS color which exceeds the max BSS color (63). + +Signed-off-by: David Bauer <mail@david-bauer.net> +--- + hostapd/config_file.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -3500,6 +3500,8 @@ static int hostapd_config_fill(struct ho + } else if (os_strcmp(buf, "he_bss_color") == 0) { + conf->he_op.he_bss_color = atoi(pos) & 0x3f; + conf->he_op.he_bss_color_disabled = 0; ++ if (atoi(pos) > 63) ++ conf->he_op.he_bss_color = os_random() % 63 + 1; + } else if (os_strcmp(buf, "he_bss_color_partial") == 0) { + conf->he_op.he_bss_color_partial = atoi(pos); + } else if (os_strcmp(buf, "he_default_pe_duration") == 0) { diff --git a/package/network/services/hostapd/patches/470-survey_data_fallback.patch b/package/network/services/hostapd/patches/470-survey_data_fallback.patch index efd82599d36..79ab48c5c27 100644 --- a/package/network/services/hostapd/patches/470-survey_data_fallback.patch +++ b/package/network/services/hostapd/patches/470-survey_data_fallback.patch @@ -1,44 +1,29 @@ --- a/src/ap/acs.c +++ b/src/ap/acs.c -@@ -302,18 +302,12 @@ static void acs_fail(struct hostapd_ifac - static long double - acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf) - { -- long double factor, busy, total; -+ long double factor, busy = 0, total; - - if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) - busy = survey->channel_time_busy; - else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX) - busy = survey->channel_time_rx; -- else { -- /* This shouldn't really happen as survey data is checked in -- * acs_sanity_check() */ -- wpa_printf(MSG_ERROR, "ACS: Survey data missing"); -- return 0; -- } - - total = survey->channel_time; - -@@ -422,20 +416,19 @@ static int acs_usable_bw160_chan(const s +@@ -455,17 +455,17 @@ static int acs_get_bw_center_chan(int fr static int acs_survey_is_sufficient(struct freq_survey *survey) { if (!(survey->filled & SURVEY_HAS_NF)) { + survey->nf = -95; - wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor"); + wpa_printf(MSG_INFO, + "ACS: Survey for freq %d is missing noise floor", + survey->freq); - return 0; } if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) { + survey->channel_time = 0; - wpa_printf(MSG_INFO, "ACS: Survey is missing channel time"); + wpa_printf(MSG_INFO, + "ACS: Survey for freq %d is missing channel time", + survey->freq); - return 0; } if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) && - !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) { +@@ -473,7 +473,6 @@ static int acs_survey_is_sufficient(stru wpa_printf(MSG_INFO, - "ACS: Survey is missing RX and busy time (at least one is required)"); + "ACS: Survey for freq %d is missing RX and busy time (at least one is required)", + survey->freq); - return 0; } diff --git a/package/network/services/hostapd/patches/500-lto-jobserver-support.patch b/package/network/services/hostapd/patches/500-lto-jobserver-support.patch index 1475590d063..67312c5004a 100644 --- a/package/network/services/hostapd/patches/500-lto-jobserver-support.patch +++ b/package/network/services/hostapd/patches/500-lto-jobserver-support.patch @@ -1,6 +1,6 @@ --- a/hostapd/Makefile +++ b/hostapd/Makefile -@@ -1293,7 +1293,7 @@ hostapd_multi.a: $(BCHECK) $(OBJS) +@@ -1396,7 +1396,7 @@ hostapd_multi.a: $(BCHECK) $(OBJS) @$(AR) cr $@ hostapd_multi.o $(OBJS) hostapd: $(OBJS) @@ -9,7 +9,7 @@ @$(E) " LD " $@ ifdef CONFIG_WPA_TRACE -@@ -1304,7 +1304,7 @@ _OBJS_VAR := OBJS_c +@@ -1407,7 +1407,7 @@ _OBJS_VAR := OBJS_c include ../src/objs.mk hostapd_cli: $(OBJS_c) @@ -20,7 +20,7 @@ NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile -@@ -1918,31 +1918,31 @@ wpa_supplicant_multi.a: .config $(BCHECK +@@ -2037,31 +2037,31 @@ wpa_supplicant_multi.a: .config $(BCHECK @$(AR) cr $@ wpa_supplicant_multi.o $(OBJS) wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs) diff --git a/package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch b/package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch new file mode 100644 index 00000000000..0efa6db9085 --- /dev/null +++ b/package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch @@ -0,0 +1,92 @@ +--- a/src/ap/hostapd.h ++++ b/src/ap/hostapd.h +@@ -163,6 +163,21 @@ struct hostapd_sae_commit_queue { + }; + + /** ++ * struct hostapd_openwrt_stats - OpenWrt custom STA/AP statistics ++ */ ++struct hostapd_openwrt_stats { ++ struct { ++ u64 neighbor_report_tx; ++ } rrm; ++ ++ struct { ++ u64 bss_transition_query_rx; ++ u64 bss_transition_request_tx; ++ u64 bss_transition_response_rx; ++ } wnm; ++}; ++ ++/** + * struct hostapd_data - hostapd per-BSS data structure + */ + struct hostapd_data { +@@ -182,6 +197,9 @@ struct hostapd_data { + + struct hostapd_data *mld_first_bss; + ++ /* OpenWrt specific statistics */ ++ struct hostapd_openwrt_stats openwrt_stats; ++ + int num_sta; /* number of entries in sta_list */ + struct sta_info *sta_list; /* STA info list head */ + #define STA_HASH_SIZE 256 +--- a/src/ap/wnm_ap.c ++++ b/src/ap/wnm_ap.c +@@ -386,6 +386,7 @@ static int ieee802_11_send_bss_trans_mgm + mgmt->u.action.u.bss_tm_req.validity_interval = 1; + pos = mgmt->u.action.u.bss_tm_req.variable; + ++ hapd->openwrt_stats.wnm.bss_transition_request_tx++; + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " + MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " + "validity_interval=%u", +@@ -790,10 +791,12 @@ int ieee802_11_rx_wnm_action_ap(struct h + plen); + return 0; + case WNM_BSS_TRANS_MGMT_QUERY: ++ hapd->openwrt_stats.wnm.bss_transition_query_rx++; + ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, + plen); + return 0; + case WNM_BSS_TRANS_MGMT_RESP: ++ hapd->openwrt_stats.wnm.bss_transition_response_rx++; + ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload, + plen); + return 0; +@@ -840,6 +843,7 @@ int wnm_send_disassoc_imminent(struct ho + + pos = mgmt->u.action.u.bss_tm_req.variable; + ++ hapd->openwrt_stats.wnm.bss_transition_request_tx++; + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " + MACSTR, disassoc_timer, MAC2STR(sta->addr)); + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { +@@ -921,6 +925,7 @@ int wnm_send_ess_disassoc_imminent(struc + return -1; + } + ++ hapd->openwrt_stats.wnm.bss_transition_request_tx++; + if (disassoc_timer) { + /* send disassociation frame after time-out */ + set_disassoc_timer(hapd, sta, disassoc_timer); +@@ -1001,6 +1006,7 @@ int wnm_send_bss_tm_req(struct hostapd_d + } + os_free(buf); + ++ hapd->openwrt_stats.wnm.bss_transition_request_tx++; + if (disassoc_timer) { + /* send disassociation frame after time-out */ + set_disassoc_timer(hapd, sta, disassoc_timer); +--- a/src/ap/rrm.c ++++ b/src/ap/rrm.c +@@ -269,6 +269,8 @@ static void hostapd_send_nei_report_resp + } + } + ++ hapd->openwrt_stats.rrm.neighbor_report_tx++; ++ + hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 005ed54e0c7..a6ccf83331f 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -1,11 +1,12 @@ --- a/hostapd/Makefile +++ b/hostapd/Makefile -@@ -166,6 +166,11 @@ OBJS += ../src/common/hw_features_common +@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common OBJS += ../src/eapol_auth/eapol_auth_sm.o +ifdef CONFIG_UBUS +CFLAGS += -DUBUS_SUPPORT ++OBJS += ../src/utils/uloop.o +OBJS += ../src/ap/ubus.o +LIBS += -lubox -lubus +endif @@ -14,7 +15,7 @@ CFLAGS += -O0 -fprofile-arcs -ftest-coverage --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h -@@ -17,6 +17,7 @@ +@@ -18,6 +18,7 @@ #include "utils/list.h" #include "ap_config.h" #include "drivers/driver.h" @@ -22,16 +23,7 @@ #define OCE_STA_CFON_ENABLED(hapd) \ ((hapd->conf->oce & OCE_STA_CFON) && \ -@@ -80,7 +81,7 @@ struct hapd_interfaces { - #ifdef CONFIG_CTRL_IFACE_UDP - unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; - #endif /* CONFIG_CTRL_IFACE_UDP */ -- -+ struct ubus_object ubus; - }; - - enum hostapd_chan_status { -@@ -154,6 +155,7 @@ struct hostapd_data { +@@ -184,6 +185,7 @@ struct hostapd_data { struct hostapd_iface *iface; struct hostapd_config *iconf; struct hostapd_bss_config *conf; @@ -39,7 +31,7 @@ int interface_added; /* virtual interface added for this BSS */ unsigned int started:1; unsigned int disabled:1; -@@ -610,6 +612,7 @@ hostapd_alloc_bss_data(struct hostapd_if +@@ -695,6 +697,7 @@ hostapd_alloc_bss_data(struct hostapd_if struct hostapd_bss_config *bss); int hostapd_setup_interface(struct hostapd_iface *iface); int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); @@ -49,7 +41,7 @@ struct hostapd_iface * hostapd_alloc_iface(void); --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c -@@ -396,6 +396,7 @@ void hostapd_free_hapd_data(struct hosta +@@ -435,6 +435,7 @@ void hostapd_free_hapd_data(struct hosta hapd->beacon_set_done = 0; wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface); @@ -57,7 +49,7 @@ accounting_deinit(hapd); hostapd_deinit_wpa(hapd); vlan_deinit(hapd); -@@ -1422,6 +1423,8 @@ static int hostapd_setup_bss(struct host +@@ -1187,6 +1188,8 @@ static int hostapd_start_beacon(struct h if (hapd->driver && hapd->driver->set_operstate) hapd->driver->set_operstate(hapd->drv_priv, 1); @@ -66,7 +58,7 @@ return 0; } -@@ -2028,6 +2031,7 @@ static int hostapd_setup_interface_compl +@@ -2275,6 +2278,7 @@ static int hostapd_setup_interface_compl if (err) goto fail; @@ -74,15 +66,15 @@ wpa_printf(MSG_DEBUG, "Completing interface initialization"); if (iface->freq) { #ifdef NEED_AP_MLME -@@ -2225,6 +2229,7 @@ dfs_offload: +@@ -2494,6 +2498,7 @@ dfs_offload: fail: wpa_printf(MSG_ERROR, "Interface initialization failed"); + hostapd_ubus_free_iface(iface); - hostapd_set_state(iface, HAPD_IFACE_DISABLED); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); - #ifdef CONFIG_FST -@@ -2700,6 +2705,7 @@ void hostapd_interface_deinit_free(struc + + if (iface->is_no_ir) { + hostapd_set_state(iface, HAPD_IFACE_NO_IR); +@@ -2984,6 +2989,7 @@ void hostapd_interface_deinit_free(struc (unsigned int) iface->conf->num_bss); driver = iface->bss[0]->driver; drv_priv = iface->bss[0]->drv_priv; @@ -92,7 +84,7 @@ __func__, driver, drv_priv); --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c -@@ -3553,13 +3553,18 @@ static void handle_auth(struct hostapd_d +@@ -2786,7 +2786,7 @@ static void handle_auth(struct hostapd_d u16 auth_alg, auth_transaction, status_code; u16 resp = WLAN_STATUS_SUCCESS; struct sta_info *sta = NULL; @@ -101,9 +93,10 @@ u16 fc; const u8 *challenge = NULL; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; - size_t resp_ies_len = 0; - u16 seq_ctrl; +@@ -2795,6 +2795,11 @@ static void handle_auth(struct hostapd_d struct radius_sta rad_info; + const u8 *dst, *sa, *bssid; + bool mld_sta = false; + struct hostapd_ubus_request req = { + .type = HOSTAPD_UBUS_AUTH_REQ, + .mgmt_frame = mgmt, @@ -112,7 +105,7 @@ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", -@@ -3727,6 +3732,13 @@ static void handle_auth(struct hostapd_d +@@ -2986,6 +2991,13 @@ static void handle_auth(struct hostapd_d resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } @@ -126,7 +119,7 @@ if (res == HOSTAPD_ACL_PENDING) return; -@@ -5454,7 +5466,7 @@ static void handle_assoc(struct hostapd_ +@@ -5161,7 +5173,7 @@ static void handle_assoc(struct hostapd_ int resp = WLAN_STATUS_SUCCESS; u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; const u8 *pos; @@ -135,7 +128,7 @@ struct sta_info *sta; u8 *tmp = NULL; #ifdef CONFIG_FILS -@@ -5667,6 +5679,11 @@ static void handle_assoc(struct hostapd_ +@@ -5374,6 +5386,11 @@ static void handle_assoc(struct hostapd_ left = res; } #endif /* CONFIG_FILS */ @@ -147,9 +140,9 @@ /* followed by SSID and Supported rates; and HT capabilities if 802.11n * is used */ -@@ -5831,6 +5848,14 @@ static void handle_assoc(struct hostapd_ - pos, left, rssi, omit_rsnxe); - os_free(tmp); +@@ -5472,6 +5489,13 @@ static void handle_assoc(struct hostapd_ + } + #endif /* CONFIG_FILS */ + ubus_resp = hostapd_ubus_handle_event(hapd, &req); + if (ubus_resp) { @@ -158,30 +151,29 @@ + resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } -+ + fail: + /* - * Remove the station in case transmission of a success response fails - * (the STA was added associated to the driver) or if the station was -@@ -5858,6 +5883,7 @@ static void handle_disassoc(struct hosta - wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", - MAC2STR(mgmt->sa), - le_to_host16(mgmt->u.disassoc.reason_code)); +@@ -5753,6 +5777,7 @@ static void handle_disassoc(struct hosta + (unsigned long) len); + return; + } + hostapd_ubus_notify(hapd, "disassoc", mgmt->sa); sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { -@@ -5927,6 +5953,8 @@ static void handle_deauth(struct hostapd + if (!sta) { +@@ -5784,6 +5809,8 @@ static void handle_deauth(struct hostapd /* Clear the PTKSA cache entries for PASN */ ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); + hostapd_ubus_notify(hapd, "deauth", mgmt->sa); + sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " + if (!sta) { + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR --- a/src/ap/beacon.c +++ b/src/ap/beacon.c -@@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat +@@ -1036,6 +1036,12 @@ void handle_probe_req(struct hostapd_dat u16 csa_offs[2]; size_t csa_offs_len; struct radius_sta rad_info; @@ -194,7 +186,7 @@ if (hapd->iconf->rssi_ignore_probe_request && ssi_signal && ssi_signal < hapd->iconf->rssi_ignore_probe_request) -@@ -1009,6 +1015,12 @@ void handle_probe_req(struct hostapd_dat +@@ -1222,6 +1228,12 @@ void handle_probe_req(struct hostapd_dat } #endif /* CONFIG_P2P */ @@ -209,7 +201,7 @@ --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c -@@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d +@@ -260,6 +260,10 @@ int hostapd_notif_assoc(struct hostapd_d u16 reason = WLAN_REASON_UNSPECIFIED; int status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; @@ -220,7 +212,7 @@ if (addr == NULL) { /* -@@ -237,6 +241,12 @@ int hostapd_notif_assoc(struct hostapd_d +@@ -396,6 +400,12 @@ int hostapd_notif_assoc(struct hostapd_d goto fail; } @@ -235,24 +227,83 @@ wpabuf_free(sta->p2p_ie); --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c -@@ -459,6 +459,7 @@ void ap_handle_timer(void *eloop_ctx, vo +@@ -471,6 +471,7 @@ void ap_handle_timer(void *eloop_ctx, vo + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " "local deauth request"); - ap_free_sta(hapd, sta); + hostapd_ubus_notify(hapd, "local-deauth", sta->addr); + ap_free_sta(hapd, sta); return; } - -@@ -614,6 +615,7 @@ skip_poll: +@@ -626,6 +627,7 @@ skip_poll: + mlme_deauthenticate_indication( hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); - ap_free_sta(hapd, sta); + hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr); + ap_free_sta(hapd, sta); break; } - } -@@ -1329,6 +1331,7 @@ void ap_sta_set_authorized(struct hostap - buf, ip_addr, keyid_buf); +@@ -1344,15 +1346,28 @@ void ap_sta_set_authorized(struct hostap + sta->addr, authorized, dev_addr); + + if (authorized) { ++ static const char * const auth_algs[] = { ++ [WLAN_AUTH_OPEN] = "open", ++ [WLAN_AUTH_SHARED_KEY] = "shared", ++ [WLAN_AUTH_FT] = "ft", ++ [WLAN_AUTH_SAE] = "sae", ++ [WLAN_AUTH_FILS_SK] = "fils-sk", ++ [WLAN_AUTH_FILS_SK_PFS] = "fils-sk-pfs", ++ [WLAN_AUTH_FILS_PK] = "fils-pk", ++ [WLAN_AUTH_PASN] = "pasn", ++ }; ++ const char *auth_alg = NULL; + const u8 *dpp_pkhash; + const char *keyid; + char dpp_pkhash_buf[100]; + char keyid_buf[100]; + char ip_addr[100]; ++ char alg_buf[100]; + + dpp_pkhash_buf[0] = '\0'; + keyid_buf[0] = '\0'; + ip_addr[0] = '\0'; ++ alg_buf[0] = '\0'; + #ifdef CONFIG_P2P + if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { + os_snprintf(ip_addr, sizeof(ip_addr), +@@ -1362,6 +1377,13 @@ void ap_sta_set_authorized(struct hostap + } + #endif /* CONFIG_P2P */ + ++ if (sta->auth_alg < ARRAY_SIZE(auth_algs)) ++ auth_alg = auth_algs[sta->auth_alg]; ++ ++ if (auth_alg) ++ os_snprintf(alg_buf, sizeof(alg_buf), ++ " auth_alg=%s", auth_alg); ++ + keyid = ap_sta_wpa_get_keyid(hapd, sta); + if (keyid) { + os_snprintf(keyid_buf, sizeof(keyid_buf), +@@ -1380,17 +1402,19 @@ void ap_sta_set_authorized(struct hostap + dpp_pkhash, SHA256_MAC_LEN); + } + +- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s", +- buf, ip_addr, keyid_buf, dpp_pkhash_buf); ++ hostapd_ubus_notify_authorized(hapd, sta, auth_alg); ++ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s%s", ++ buf, ip_addr, keyid_buf, dpp_pkhash_buf, alg_buf); + + if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx) + wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, +- AP_STA_CONNECTED "%s%s%s%s", ++ AP_STA_CONNECTED "%s%s%s%s%s", + buf, ip_addr, keyid_buf, +- dpp_pkhash_buf); ++ dpp_pkhash_buf, alg_buf); } else { wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); + hostapd_ubus_notify(hapd, "disassoc", sta->addr); @@ -261,7 +312,7 @@ hapd->msg_ctx_parent != hapd->msg_ctx) --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c -@@ -265,6 +265,7 @@ static void hostapd_wpa_auth_psk_failure +@@ -269,6 +269,7 @@ static void hostapd_wpa_auth_psk_failure struct hostapd_data *hapd = ctx; wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, MAC2STR(addr)); @@ -271,20 +322,21 @@ --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile -@@ -176,6 +176,12 @@ ifdef CONFIG_EAPOL_TEST +@@ -192,6 +192,13 @@ ifdef CONFIG_EAPOL_TEST CFLAGS += -Werror -DEAPOL_TEST endif +ifdef CONFIG_UBUS +CFLAGS += -DUBUS_SUPPORT +OBJS += ubus.o ++OBJS += ../src/utils/uloop.o +LIBS += -lubox -lubus +endif + ifdef CONFIG_CODE_COVERAGE CFLAGS += -O0 -fprofile-arcs -ftest-coverage LIBS += -lgcov -@@ -959,6 +965,9 @@ ifdef CONFIG_CTRL_IFACE_MIB +@@ -987,6 +994,9 @@ ifdef CONFIG_CTRL_IFACE_MIB CFLAGS += -DCONFIG_CTRL_IFACE_MIB endif OBJS += ../src/ap/ctrl_iface_ap.o @@ -296,7 +348,7 @@ CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -7017,6 +7017,8 @@ struct wpa_supplicant * wpa_supplicant_a +@@ -7595,6 +7595,8 @@ struct wpa_supplicant * wpa_supplicant_a } #endif /* CONFIG_P2P */ @@ -305,7 +357,7 @@ return wpa_s; } -@@ -7043,6 +7045,8 @@ int wpa_supplicant_remove_iface(struct w +@@ -7621,6 +7623,8 @@ int wpa_supplicant_remove_iface(struct w struct wpa_supplicant *parent = wpa_s->parent; #endif /* CONFIG_MESH */ @@ -314,7 +366,7 @@ /* Remove interface from the global list of interfaces */ prev = global->ifaces; if (prev == wpa_s) { -@@ -7346,8 +7350,12 @@ int wpa_supplicant_run(struct wpa_global +@@ -7967,8 +7971,12 @@ int wpa_supplicant_run(struct wpa_global eloop_register_signal_terminate(wpa_supplicant_terminate, global); eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); @@ -329,15 +381,15 @@ --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h -@@ -19,6 +19,7 @@ - #include "wps/wps_defs.h" +@@ -21,6 +21,7 @@ #include "config_ssid.h" #include "wmm_ac.h" + #include "pasn/pasn_common.h" +#include "ubus.h" extern const char *const wpa_supplicant_version; extern const char *const wpa_supplicant_license; -@@ -321,6 +322,8 @@ struct wpa_global { +@@ -319,6 +320,8 @@ struct wpa_global { #endif /* CONFIG_WIFI_DISPLAY */ struct psk_list_entry *add_psk; /* From group formation */ @@ -346,7 +398,7 @@ }; -@@ -605,6 +608,7 @@ struct wpa_supplicant { +@@ -685,6 +688,7 @@ struct wpa_supplicant { unsigned char own_addr[ETH_ALEN]; unsigned char perm_addr[ETH_ALEN]; char ifname[100]; @@ -364,7 +416,7 @@ #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG -@@ -392,6 +393,8 @@ static int wpa_supplicant_wps_cred(void +@@ -402,6 +403,8 @@ static int wpa_supplicant_wps_cred(void wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", cred->cred_attr, cred->cred_attr_len); @@ -373,36 +425,18 @@ if (wpa_s->conf->wps_cred_processing == 1) return 0; ---- a/hostapd/main.c -+++ b/hostapd/main.c -@@ -895,6 +895,7 @@ int main(int argc, char *argv[]) - } - - hostapd_global_ctrl_iface_init(&interfaces); -+ hostapd_ubus_add(&interfaces); - - if (hostapd_global_run(&interfaces, daemonize, pid_file)) { - wpa_printf(MSG_ERROR, "Failed to start eloop"); -@@ -904,6 +905,7 @@ int main(int argc, char *argv[]) - ret = 0; - - out: -+ hostapd_ubus_free(&interfaces); - hostapd_global_ctrl_iface_deinit(&interfaces); - /* Deinitialize all interfaces */ - for (i = 0; i < interfaces.count; i++) { --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -203,7 +203,7 @@ int main(int argc, char *argv[]) for (;;) { c = getopt(argc, argv, -- "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuv::W"); -+ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:nNo:O:p:P:qsTtuv::W"); +- "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuv::W"); ++ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:nNo:O:p:P:qsTtuv::W"); if (c < 0) break; switch (c) { -@@ -271,6 +271,9 @@ int main(int argc, char *argv[]) +@@ -268,6 +268,9 @@ int main(int argc, char *argv[]) params.conf_p2p_dev = optarg; break; #endif /* CONFIG_P2P */ @@ -424,6 +458,16 @@ } +@@ -352,6 +355,9 @@ void hostapd_handle_radio_measurement(st + mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa)); + + switch (mgmt->u.action.u.rrm.action) { ++ case WLAN_RRM_LINK_MEASUREMENT_REPORT: ++ hostapd_ubus_handle_link_measurement(hapd, buf, len); ++ break; + case WLAN_RRM_RADIO_MEASUREMENT_REPORT: + hostapd_handle_radio_msmt_report(hapd, buf, len); + break; --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -22,6 +22,7 @@ @@ -464,7 +508,7 @@ --- a/src/ap/dfs.c +++ b/src/ap/dfs.c -@@ -1193,6 +1193,8 @@ int hostapd_dfs_radar_detected(struct ho +@@ -1216,6 +1216,8 @@ int hostapd_dfs_pre_cac_expired(struct h "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", freq, ht_enabled, chan_offset, chan_width, cf1, cf2); @@ -506,7 +550,7 @@ } --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h -@@ -324,6 +324,7 @@ struct sta_info { +@@ -322,6 +322,7 @@ struct sta_info { #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_AIRTIME_POLICY unsigned int airtime_weight; @@ -514,3 +558,191 @@ struct os_reltime backlogged_until; #endif /* CONFIG_AIRTIME_POLICY */ +--- a/src/ap/wnm_ap.c ++++ b/src/ap/wnm_ap.c +@@ -455,7 +455,8 @@ static void ieee802_11_rx_bss_trans_mgmt + MAC2STR(addr), reason, hex ? " neighbor=" : "", hex); + os_free(hex); + +- ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token); ++ if (!hostapd_ubus_notify_bss_transition_query(hapd, addr, dialog_token, reason, pos, end - pos)) ++ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token); + } + + +@@ -477,7 +478,7 @@ static void ieee802_11_rx_bss_trans_mgmt + size_t len) + { + u8 dialog_token, status_code, bss_termination_delay; +- const u8 *pos, *end; ++ const u8 *pos, *end, *target_bssid = NULL; + int enabled = hapd->conf->bss_transition; + struct sta_info *sta; + +@@ -524,6 +525,7 @@ static void ieee802_11_rx_bss_trans_mgmt + wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); + return; + } ++ target_bssid = pos; + sta->agreed_to_steer = 1; + eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); + eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer, +@@ -543,6 +545,10 @@ static void ieee802_11_rx_bss_trans_mgmt + MAC2STR(addr), status_code, bss_termination_delay); + } + ++ hostapd_ubus_notify_bss_transition_response(hapd, sta->addr, dialog_token, ++ status_code, bss_termination_delay, ++ target_bssid, pos, end - pos); ++ + wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", + pos, end - pos); + } +--- a/src/utils/eloop.c ++++ b/src/utils/eloop.c +@@ -77,6 +77,9 @@ struct eloop_sock_table { + struct eloop_data { + int max_sock; + ++ eloop_timeout_poll_handler timeout_poll_cb; ++ eloop_poll_handler poll_cb; ++ + size_t count; /* sum of all table counts */ + #ifdef CONFIG_ELOOP_POLL + size_t max_pollfd_map; /* number of pollfds_map currently allocated */ +@@ -1121,6 +1124,12 @@ void eloop_run(void) + os_reltime_sub(&timeout->time, &now, &tv); + else + tv.sec = tv.usec = 0; ++ } ++ ++ if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout)) ++ timeout = (void *)1; ++ ++ if (timeout) { + #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) + timeout_ms = tv.sec * 1000 + tv.usec / 1000; + #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */ +@@ -1190,7 +1199,8 @@ void eloop_run(void) + eloop.exceptions.changed = 0; + + eloop_process_pending_signals(); +- ++ if (eloop.poll_cb) ++ eloop.poll_cb(); + + /* check if some registered timeouts have occurred */ + timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, +@@ -1252,6 +1262,14 @@ out: + return; + } + ++int eloop_register_cb(eloop_poll_handler poll_cb, ++ eloop_timeout_poll_handler timeout_cb) ++{ ++ eloop.poll_cb = poll_cb; ++ eloop.timeout_poll_cb = timeout_cb; ++ ++ return 0; ++} + + void eloop_terminate(void) + { +--- a/src/utils/eloop.h ++++ b/src/utils/eloop.h +@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo + */ + typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); + ++typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set); ++typedef void (*eloop_poll_handler)(void); ++ + /** + * eloop_init() - Initialize global event loop data + * Returns: 0 on success, -1 on failure +@@ -73,6 +76,9 @@ typedef void (*eloop_signal_handler)(int + */ + int eloop_init(void); + ++int eloop_register_cb(eloop_poll_handler poll_cb, ++ eloop_timeout_poll_handler timeout_cb); ++ + /** + * eloop_register_read_sock - Register handler for read events + * @sock: File descriptor number for the socket +@@ -320,6 +326,8 @@ int eloop_register_signal_reconfig(eloop + */ + int eloop_sock_requeue(void); + ++void eloop_add_uloop(void); ++ + /** + * eloop_run - Start the event loop + * +--- /dev/null ++++ b/src/utils/uloop.c +@@ -0,0 +1,64 @@ ++#include <libubox/uloop.h> ++#include "includes.h" ++#include "common.h" ++#include "eloop.h" ++ ++static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++} ++ ++static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events) ++{ ++ unsigned int changed = events ^ fd->flags; ++ ++ if (changed & ULOOP_READ) { ++ if (events & ULOOP_READ) ++ eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd); ++ else ++ eloop_unregister_sock(fd->fd, EVENT_TYPE_READ); ++ } ++ ++ if (changed & ULOOP_WRITE) { ++ if (events & ULOOP_WRITE) ++ eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd); ++ else ++ eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE); ++ } ++} ++ ++static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set) ++{ ++ struct os_reltime tv_uloop; ++ int timeout_ms = uloop_get_next_timeout(); ++ ++ if (timeout_ms < 0) ++ return false; ++ ++ tv_uloop.sec = timeout_ms / 1000; ++ tv_uloop.usec = (timeout_ms % 1000) * 1000; ++ ++ if (!tv_set || os_reltime_before(&tv_uloop, tv)) { ++ *tv = tv_uloop; ++ return true; ++ } ++ ++ return false; ++} ++ ++static void uloop_poll_handler(void) ++{ ++ uloop_run_timeout(0); ++} ++ ++void eloop_add_uloop(void) ++{ ++ static bool init_done = false; ++ ++ if (!init_done) { ++ uloop_init(); ++ uloop_fd_set_cb = eloop_uloop_fd_cb; ++ init_done = true; ++ } ++ ++ eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler); ++} diff --git a/package/network/services/hostapd/patches/601-ucode_support.patch b/package/network/services/hostapd/patches/601-ucode_support.patch new file mode 100644 index 00000000000..cfdb51f356c --- /dev/null +++ b/package/network/services/hostapd/patches/601-ucode_support.patch @@ -0,0 +1,671 @@ +--- a/hostapd/Makefile ++++ b/hostapd/Makefile +@@ -168,9 +168,21 @@ OBJS += ../src/eapol_auth/eapol_auth_sm. + + ifdef CONFIG_UBUS + CFLAGS += -DUBUS_SUPPORT +-OBJS += ../src/utils/uloop.o + OBJS += ../src/ap/ubus.o +-LIBS += -lubox -lubus ++LIBS += -lubus ++NEED_ULOOP:=y ++endif ++ ++ifdef CONFIG_UCODE ++CFLAGS += -DUCODE_SUPPORT ++OBJS += ../src/utils/ucode.o ++OBJS += ../src/ap/ucode.o ++NEED_ULOOP:=y ++endif ++ ++ifdef NEED_ULOOP ++OBJS += ../src/utils/uloop.o ++LIBS += -lubox + endif + + ifdef CONFIG_CODE_COVERAGE +--- a/hostapd/main.c ++++ b/hostapd/main.c +@@ -1007,6 +1007,7 @@ int main(int argc, char *argv[]) + } + + hostapd_global_ctrl_iface_init(&interfaces); ++ hostapd_ucode_init(&interfaces); + + if (hostapd_global_run(&interfaces, daemonize, pid_file)) { + wpa_printf(MSG_ERROR, "Failed to start eloop"); +@@ -1016,6 +1017,7 @@ int main(int argc, char *argv[]) + ret = 0; + + out: ++ hostapd_ucode_free(); + hostapd_global_ctrl_iface_deinit(&interfaces); + /* Deinitialize all interfaces */ + for (i = 0; i < interfaces.count; i++) { +--- a/src/ap/hostapd.h ++++ b/src/ap/hostapd.h +@@ -19,6 +19,7 @@ + #include "ap_config.h" + #include "drivers/driver.h" + #include "ubus.h" ++#include "ucode.h" + + #define OCE_STA_CFON_ENABLED(hapd) \ + ((hapd->conf->oce & OCE_STA_CFON) && \ +@@ -51,6 +52,10 @@ struct hapd_interfaces { + struct hostapd_config * (*config_read_cb)(const char *config_fname); + int (*ctrl_iface_init)(struct hostapd_data *hapd); + void (*ctrl_iface_deinit)(struct hostapd_data *hapd); ++ int (*ctrl_iface_recv)(struct hostapd_data *hapd, ++ char *buf, char *reply, int reply_size, ++ struct sockaddr_storage *from, ++ socklen_t fromlen); + int (*for_each_interface)(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); +@@ -186,6 +191,7 @@ struct hostapd_data { + struct hostapd_config *iconf; + struct hostapd_bss_config *conf; + struct hostapd_ubus_bss ubus; ++ struct hostapd_ucode_bss ucode; + int interface_added; /* virtual interface added for this BSS */ + unsigned int started:1; + unsigned int disabled:1; +@@ -506,6 +512,7 @@ struct hostapd_sta_info { + */ + struct hostapd_iface { + struct hapd_interfaces *interfaces; ++ struct hostapd_ucode_iface ucode; + void *owner; + char *config_fname; + struct hostapd_config *conf; +@@ -706,6 +713,8 @@ struct hostapd_iface * hostapd_init(stru + struct hostapd_iface * + hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, + const char *config_fname, int debug); ++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon); ++void hostapd_bss_deinit(struct hostapd_data *hapd); + void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc); + void hostapd_interface_deinit_free(struct hostapd_iface *iface); +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -252,6 +252,8 @@ int hostapd_reload_config(struct hostapd + struct hostapd_config *newconf, *oldconf; + size_t j; + ++ hostapd_ucode_reload_bss(hapd); ++ + if (iface->config_fname == NULL) { + /* Only in-memory config in use - assume it has been updated */ + hostapd_clear_old(iface); +@@ -435,6 +437,7 @@ void hostapd_free_hapd_data(struct hosta + hapd->beacon_set_done = 0; + + wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface); ++ hostapd_ucode_free_bss(hapd); + hostapd_ubus_free_bss(hapd); + accounting_deinit(hapd); + hostapd_deinit_wpa(hapd); +@@ -600,6 +603,7 @@ void hostapd_cleanup_iface_partial(struc + static void hostapd_cleanup_iface(struct hostapd_iface *iface) + { + wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); ++ hostapd_ucode_free_iface(iface); + eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, + NULL); + +@@ -1189,6 +1193,7 @@ static int hostapd_start_beacon(struct h + hapd->driver->set_operstate(hapd->drv_priv, 1); + + hostapd_ubus_add_bss(hapd); ++ hostapd_ucode_add_bss(hapd); + + return 0; + } +@@ -1211,8 +1216,7 @@ static int hostapd_start_beacon(struct h + * initialized. Most of the modules that are initialized here will be + * deinitialized in hostapd_cleanup(). + */ +-static int hostapd_setup_bss(struct hostapd_data *hapd, int first, +- bool start_beacon) ++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon) + { + struct hostapd_bss_config *conf = hapd->conf; + u8 ssid[SSID_MAX_LEN + 1]; +@@ -2698,7 +2702,7 @@ hostapd_alloc_bss_data(struct hostapd_if + } + + +-static void hostapd_bss_deinit(struct hostapd_data *hapd) ++void hostapd_bss_deinit(struct hostapd_data *hapd) + { + if (!hapd) + return; +@@ -3491,7 +3495,8 @@ int hostapd_remove_iface(struct hapd_int + hapd_iface = interfaces->iface[i]; + if (hapd_iface == NULL) + return -1; +- if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { ++ if (!os_strcmp(hapd_iface->phy, buf) || ++ !os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { + wpa_printf(MSG_INFO, "Remove interface '%s'", buf); + hapd_iface->driver_ap_teardown = + !!(hapd_iface->drv_flags & +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -195,8 +195,20 @@ endif + ifdef CONFIG_UBUS + CFLAGS += -DUBUS_SUPPORT + OBJS += ubus.o ++LIBS += -lubus ++NEED_ULOOP:=y ++endif ++ ++ifdef CONFIG_UCODE ++CFLAGS += -DUCODE_SUPPORT ++OBJS += ../src/utils/ucode.o ++OBJS += ucode.o ++NEED_ULOOP:=y ++endif ++ ++ifdef NEED_ULOOP + OBJS += ../src/utils/uloop.o +-LIBS += -lubox -lubus ++LIBS += -lubox + endif + + ifdef CONFIG_CODE_COVERAGE +@@ -997,6 +1009,9 @@ OBJS += ../src/ap/ctrl_iface_ap.o + ifdef CONFIG_UBUS + OBJS += ../src/ap/ubus.o + endif ++ifdef CONFIG_UCODE ++OBJS += ../src/ap/ucode.o ++endif + endif + + CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY +--- a/wpa_supplicant/wpa_supplicant.c ++++ b/wpa_supplicant/wpa_supplicant.c +@@ -1044,6 +1044,7 @@ void wpa_supplicant_set_state(struct wpa + sme_sched_obss_scan(wpa_s, 0); + } + wpa_s->wpa_state = state; ++ wpas_ucode_update_state(wpa_s); + + #ifdef CONFIG_BGSCAN + if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid) +@@ -7594,6 +7595,7 @@ struct wpa_supplicant * wpa_supplicant_a + #endif /* CONFIG_P2P */ + + wpas_ubus_add_bss(wpa_s); ++ wpas_ucode_add_bss(wpa_s); + + return wpa_s; + } +@@ -7621,6 +7623,7 @@ int wpa_supplicant_remove_iface(struct w + struct wpa_supplicant *parent = wpa_s->parent; + #endif /* CONFIG_MESH */ + ++ wpas_ucode_free_bss(wpa_s); + wpas_ubus_free_bss(wpa_s); + + /* Remove interface from the global list of interfaces */ +@@ -7931,6 +7934,7 @@ struct wpa_global * wpa_supplicant_init( + + eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0, + wpas_periodic, global, NULL); ++ wpas_ucode_init(global); + + return global; + } +@@ -7969,12 +7973,8 @@ int wpa_supplicant_run(struct wpa_global + eloop_register_signal_terminate(wpa_supplicant_terminate, global); + eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); + +- wpas_ubus_add(global); +- + eloop_run(); + +- wpas_ubus_free(global); +- + return 0; + } + +@@ -8007,6 +8007,8 @@ void wpa_supplicant_deinit(struct wpa_gl + + wpas_notify_supplicant_deinitialized(global); + ++ wpas_ucode_free(); ++ + eap_peer_unregister_methods(); + #ifdef CONFIG_AP + eap_server_unregister_methods(); +--- a/wpa_supplicant/wpa_supplicant_i.h ++++ b/wpa_supplicant/wpa_supplicant_i.h +@@ -22,6 +22,7 @@ + #include "wmm_ac.h" + #include "pasn/pasn_common.h" + #include "ubus.h" ++#include "ucode.h" + + extern const char *const wpa_supplicant_version; + extern const char *const wpa_supplicant_license; +@@ -689,6 +690,7 @@ struct wpa_supplicant { + unsigned char perm_addr[ETH_ALEN]; + char ifname[100]; + struct wpas_ubus_bss ubus; ++ struct wpas_ucode_bss ucode; + #ifdef CONFIG_MATCH_IFACE + int matched; + #endif /* CONFIG_MATCH_IFACE */ +--- a/hostapd/ctrl_iface.c ++++ b/hostapd/ctrl_iface.c +@@ -4856,6 +4856,7 @@ try_again: + return -1; + } + ++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process; + wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); + + return 0; +@@ -4957,6 +4958,7 @@ fail: + os_free(fname); + + interface->global_ctrl_sock = s; ++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process; + eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, + interface, NULL); + +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -3787,6 +3787,25 @@ struct wpa_driver_ops { + const char *ifname); + + /** ++ * if_rename - Rename a virtual interface ++ * @priv: Private driver interface data ++ * @type: Interface type ++ * @ifname: Interface name of the virtual interface to be renamed ++ * (NULL when renaming the AP BSS interface) ++ * @new_name: New interface name of the virtual interface ++ * Returns: 0 on success, -1 on failure ++ */ ++ int (*if_rename)(void *priv, enum wpa_driver_if_type type, ++ const char *ifname, const char *new_name); ++ ++ /** ++ * set_first_bss - Make a virtual interface the first (primary) bss ++ * @priv: Private driver interface data ++ * Returns: 0 on success, -1 on failure ++ */ ++ int (*set_first_bss)(void *priv); ++ ++ /** + * set_sta_vlan - Bind a station into a specific interface (AP only) + * @priv: Private driver interface data + * @ifname: Interface (main or virtual BSS or VLAN) +@@ -6440,6 +6459,7 @@ union wpa_event_data { + + /** + * struct ch_switch ++ * @count: Count until channel switch activates + * @freq: Frequency of new channel in MHz + * @ht_enabled: Whether this is an HT channel + * @ch_offset: Secondary channel offset +@@ -6450,6 +6470,7 @@ union wpa_event_data { + * @punct_bitmap: Puncturing bitmap + */ + struct ch_switch { ++ int count; + int freq; + int ht_enabled; + int ch_offset; +--- a/src/drivers/driver_nl80211_event.c ++++ b/src/drivers/driver_nl80211_event.c +@@ -1202,6 +1202,7 @@ static void mlme_event_ch_switch(struct + struct nlattr *bw, struct nlattr *cf1, + struct nlattr *cf2, + struct nlattr *punct_bitmap, ++ struct nlattr *count, + int finished) + { + struct i802_bss *bss; +@@ -1265,6 +1266,8 @@ static void mlme_event_ch_switch(struct + data.ch_switch.cf1 = nla_get_u32(cf1); + if (cf2) + data.ch_switch.cf2 = nla_get_u32(cf2); ++ if (count) ++ data.ch_switch.count = nla_get_u32(count); + + if (finished) + bss->flink->freq = data.ch_switch.freq; +@@ -3912,6 +3915,7 @@ static void do_process_drv_event(struct + tb[NL80211_ATTR_CENTER_FREQ1], + tb[NL80211_ATTR_CENTER_FREQ2], + tb[NL80211_ATTR_PUNCT_BITMAP], ++ tb[NL80211_ATTR_CH_SWITCH_COUNT], + 0); + break; + case NL80211_CMD_CH_SWITCH_NOTIFY: +@@ -3924,6 +3928,7 @@ static void do_process_drv_event(struct + tb[NL80211_ATTR_CENTER_FREQ1], + tb[NL80211_ATTR_CENTER_FREQ2], + tb[NL80211_ATTR_PUNCT_BITMAP], ++ NULL, + 1); + break; + case NL80211_CMD_DISCONNECT: +--- a/wpa_supplicant/events.c ++++ b/wpa_supplicant/events.c +@@ -5389,6 +5389,7 @@ void supplicant_event(void *ctx, enum wp + event_to_string(event), event); + #endif /* CONFIG_NO_STDOUT_DEBUG */ + ++ wpas_ucode_event(wpa_s, event, data); + switch (event) { + case EVENT_AUTH: + #ifdef CONFIG_FST +--- a/src/ap/ap_drv_ops.h ++++ b/src/ap/ap_drv_ops.h +@@ -393,6 +393,23 @@ static inline int hostapd_drv_stop_ap(st + return hapd->driver->stop_ap(hapd->drv_priv); + } + ++static inline int hostapd_drv_if_rename(struct hostapd_data *hapd, ++ enum wpa_driver_if_type type, ++ const char *ifname, ++ const char *new_name) ++{ ++ if (!hapd->driver || !hapd->driver->if_rename || !hapd->drv_priv) ++ return -1; ++ return hapd->driver->if_rename(hapd->drv_priv, type, ifname, new_name); ++} ++ ++static inline int hostapd_drv_set_first_bss(struct hostapd_data *hapd) ++{ ++ if (!hapd->driver || !hapd->driver->set_first_bss || !hapd->drv_priv) ++ return 0; ++ return hapd->driver->set_first_bss(hapd->drv_priv); ++} ++ + static inline int hostapd_drv_channel_info(struct hostapd_data *hapd, + struct wpa_channel_info *ci) + { +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -73,6 +73,16 @@ enum nlmsgerr_attrs { + + #endif /* ANDROID */ + ++static void handle_nl_debug_hook(struct nl_msg *msg, int tx) ++{ ++ const struct nlmsghdr *nlh; ++ ++ if (!wpa_netlink_hook) ++ return; ++ ++ nlh = nlmsg_hdr(msg); ++ wpa_netlink_hook(tx, nlh, nlh->nlmsg_len); ++} + + static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg) + { +@@ -379,6 +389,11 @@ static int no_seq_check(struct nl_msg *m + return NL_OK; + } + ++static int debug_handler(struct nl_msg *msg, void *arg) ++{ ++ handle_nl_debug_hook(msg, 0); ++ return NL_OK; ++} + + static void nl80211_nlmsg_clear(struct nl_msg *msg) + { +@@ -415,6 +430,7 @@ static int send_and_recv(struct nl80211_ + if (!msg) + return -ENOMEM; + ++ handle_nl_debug_hook(msg, 1); + cb = nl_cb_clone(global->nl_cb); + if (!cb) + goto out; +@@ -443,6 +459,7 @@ static int send_and_recv(struct nl80211_ + + err = 1; + ++ nl_cb_set(cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL); + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); + if (ack_handler_custom) { +@@ -919,6 +936,7 @@ nl80211_get_wiphy_data_ap(struct i802_bs + os_free(w); + return NULL; + } ++ nl_cb_set(w->nl_cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL); + nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, +@@ -1333,7 +1351,7 @@ static void wpa_driver_nl80211_event_rtm + } + wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)", + namebuf, ifname); +- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) { ++ if (drv->first_bss->ifindex != ifi->ifi_index) { + wpa_printf(MSG_DEBUG, + "nl80211: Not the main interface (%s) - do not indicate interface down", + drv->first_bss->ifname); +@@ -1369,7 +1387,7 @@ static void wpa_driver_nl80211_event_rtm + } + wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)", + namebuf, ifname); +- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) { ++ if (drv->first_bss->ifindex != ifi->ifi_index) { + wpa_printf(MSG_DEBUG, + "nl80211: Not the main interface (%s) - do not indicate interface up", + drv->first_bss->ifname); +@@ -1992,6 +2010,7 @@ static int wpa_driver_nl80211_init_nl_gl + /* Continue without vendor events */ + } + ++ nl_cb_set(global->nl_cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL); + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, +@@ -2160,6 +2179,7 @@ static int nl80211_init_bss(struct i802_ + if (!bss->nl_cb) + return -1; + ++ nl_cb_set(bss->nl_cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL); + nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, +@@ -8432,6 +8452,7 @@ static void *i802_init(struct hostapd_da + char master_ifname[IFNAMSIZ]; + int ifindex, br_ifindex = 0; + int br_added = 0; ++ int err; + + bss = wpa_driver_nl80211_drv_init(hapd, params->ifname, + params->global_priv, 1, +@@ -8491,21 +8512,17 @@ static void *i802_init(struct hostapd_da + (params->num_bridge == 0 || !params->bridge[0])) + add_ifidx(drv, br_ifindex, drv->ifindex); + +- if (bss->added_if_into_bridge || bss->already_in_bridge) { +- int err; +- +- drv->rtnl_sk = nl_socket_alloc(); +- if (drv->rtnl_sk == NULL) { +- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock"); +- goto failed; +- } ++ drv->rtnl_sk = nl_socket_alloc(); ++ if (drv->rtnl_sk == NULL) { ++ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock"); ++ goto failed; ++ } + +- err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE); +- if (err) { +- wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s", +- nl_geterror(err)); +- goto failed; +- } ++ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE); ++ if (err) { ++ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s", ++ nl_geterror(err)); ++ goto failed; + } + + if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) { +@@ -8875,6 +8892,50 @@ static int wpa_driver_nl80211_if_remove( + return 0; + } + ++static int wpa_driver_nl80211_if_rename(struct i802_bss *bss, ++ enum wpa_driver_if_type type, ++ const char *ifname, const char *new_name) ++{ ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ struct ifinfomsg ifi = { ++ .ifi_family = AF_UNSPEC, ++ .ifi_index = bss->ifindex, ++ }; ++ struct nl_msg *msg; ++ int res = -ENOMEM; ++ ++ if (ifname) ++ ifi.ifi_index = if_nametoindex(ifname); ++ ++ msg = nlmsg_alloc_simple(RTM_SETLINK, 0); ++ if (!msg) ++ return res; ++ ++ if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) ++ goto out; ++ ++ if (nla_put_string(msg, IFLA_IFNAME, new_name)) ++ goto out; ++ ++ res = nl_send_auto_complete(drv->rtnl_sk, msg); ++ if (res < 0) ++ goto out; ++ ++ res = nl_wait_for_ack(drv->rtnl_sk); ++ if (res) { ++ wpa_printf(MSG_INFO, ++ "nl80211: Renaming device %s to %s failed: %s", ++ ifname ? ifname : bss->ifname, new_name, nl_geterror(res)); ++ goto out; ++ } ++ ++ if (type == WPA_IF_AP_BSS && !ifname) ++ os_strlcpy(bss->ifname, new_name, sizeof(bss->ifname)); ++ ++out: ++ nlmsg_free(msg); ++ return res; ++} + + static int cookie_handler(struct nl_msg *msg, void *arg) + { +@@ -10513,6 +10574,37 @@ static int driver_nl80211_if_remove(void + } + + ++static int driver_nl80211_if_rename(void *priv, enum wpa_driver_if_type type, ++ const char *ifname, const char *new_name) ++{ ++ struct i802_bss *bss = priv; ++ return wpa_driver_nl80211_if_rename(bss, type, ifname, new_name); ++} ++ ++ ++static int driver_nl80211_set_first_bss(void *priv) ++{ ++ struct i802_bss *bss = priv, *tbss; ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ ++ if (drv->first_bss == bss) ++ return 0; ++ ++ for (tbss = drv->first_bss; tbss; tbss = tbss->next) { ++ if (tbss->next != bss) ++ continue; ++ ++ tbss->next = bss->next; ++ bss->next = drv->first_bss; ++ drv->first_bss = bss; ++ drv->ctx = bss->ctx; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++ + static int driver_nl80211_send_mlme(void *priv, const u8 *data, + size_t data_len, int noack, + unsigned int freq, +@@ -13697,6 +13789,8 @@ const struct wpa_driver_ops wpa_driver_n + .set_acl = wpa_driver_nl80211_set_acl, + .if_add = wpa_driver_nl80211_if_add, + .if_remove = driver_nl80211_if_remove, ++ .if_rename = driver_nl80211_if_rename, ++ .set_first_bss = driver_nl80211_set_first_bss, + .send_mlme = driver_nl80211_send_mlme, + .get_hw_feature_data = nl80211_get_hw_feature_data, + .sta_add = wpa_driver_nl80211_sta_add, +--- a/src/utils/wpa_debug.c ++++ b/src/utils/wpa_debug.c +@@ -26,6 +26,10 @@ static FILE *wpa_debug_tracing_file = NU + #define WPAS_TRACE_PFX "wpas <%d>: " + #endif /* CONFIG_DEBUG_LINUX_TRACING */ + ++void (*wpa_printf_hook)(int level, const char *fmt, va_list ap); ++void (*wpa_hexdump_hook)(int level, const char *title, const void *buf, ++ size_t len); ++void (*wpa_netlink_hook)(int tx, const void *data, size_t len); + + int wpa_debug_level = MSG_INFO; + int wpa_debug_show_keys = 0; +@@ -210,6 +214,12 @@ void _wpa_printf(int level, const char * + { + va_list ap; + ++ if (wpa_printf_hook) { ++ va_start(ap, fmt); ++ wpa_printf_hook(level, fmt, ap); ++ va_end(ap); ++ } ++ + if (level >= wpa_debug_level) { + #ifdef CONFIG_ANDROID_LOG + va_start(ap, fmt); +@@ -260,6 +270,9 @@ void _wpa_hexdump(int level, const char + { + size_t i; + ++ if (wpa_hexdump_hook) ++ wpa_hexdump_hook(level, title, buf, len); ++ + #ifdef CONFIG_DEBUG_LINUX_TRACING + if (wpa_debug_tracing_file != NULL) { + fprintf(wpa_debug_tracing_file, +--- a/src/utils/wpa_debug.h ++++ b/src/utils/wpa_debug.h +@@ -11,6 +11,10 @@ + + #include "wpabuf.h" + ++extern void (*wpa_printf_hook)(int level, const char *fmt, va_list ap); ++extern void (*wpa_hexdump_hook)(int level, const char *title, ++ const void *buf, size_t len); ++extern void (*wpa_netlink_hook)(int tx, const void *data, size_t len); + extern int wpa_debug_level; + extern int wpa_debug_show_keys; + extern int wpa_debug_timestamp; diff --git a/package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch b/package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch new file mode 100644 index 00000000000..a03fcc9f92b --- /dev/null +++ b/package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch @@ -0,0 +1,33 @@ +--- a/src/common/wpa_ctrl.c ++++ b/src/common/wpa_ctrl.c +@@ -135,7 +135,7 @@ try_again: + return NULL; + } + tries++; +-#ifdef ANDROID ++ + /* Set client socket file permissions so that bind() creates the client + * socket with these permissions and there is no need to try to change + * them with chmod() after bind() which would have potential issues with +@@ -147,7 +147,7 @@ try_again: + * operations to allow the response to go through. Those are using the + * no-deference-symlinks version to avoid races. */ + fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +-#endif /* ANDROID */ ++ + if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, + sizeof(ctrl->local)) < 0) { + if (errno == EADDRINUSE && tries < 2) { +@@ -165,7 +165,11 @@ try_again: + return NULL; + } + +-#ifdef ANDROID ++#ifndef ANDROID ++ /* Set group even if we do not have privileges to change owner */ ++ lchown(ctrl->local.sun_path, -1, 101); ++ lchown(ctrl->local.sun_path, 101, 101); ++#else + /* Set group even if we do not have privileges to change owner */ + lchown(ctrl->local.sun_path, -1, AID_WIFI); + lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); diff --git a/package/network/services/hostapd/patches/700-wifi-reload.patch b/package/network/services/hostapd/patches/700-wifi-reload.patch deleted file mode 100644 index 5993b0d4450..00000000000 --- a/package/network/services/hostapd/patches/700-wifi-reload.patch +++ /dev/null @@ -1,220 +0,0 @@ ---- a/hostapd/config_file.c -+++ b/hostapd/config_file.c -@@ -2453,6 +2453,8 @@ static int hostapd_config_fill(struct ho - bss->isolate = atoi(pos); - } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { - bss->ap_max_inactivity = atoi(pos); -+ } else if (os_strcmp(buf, "config_id") == 0) { -+ bss->config_id = os_strdup(pos); - } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { - bss->skip_inactivity_poll = atoi(pos); - } else if (os_strcmp(buf, "country_code") == 0) { -@@ -3153,6 +3155,8 @@ static int hostapd_config_fill(struct ho - } - } else if (os_strcmp(buf, "acs_exclude_dfs") == 0) { - conf->acs_exclude_dfs = atoi(pos); -+ } else if (os_strcmp(buf, "radio_config_id") == 0) { -+ conf->config_id = os_strdup(pos); - } else if (os_strcmp(buf, "op_class") == 0) { - conf->op_class = atoi(pos); - } else if (os_strcmp(buf, "channel") == 0) { ---- a/src/ap/ap_config.c -+++ b/src/ap/ap_config.c -@@ -791,6 +791,7 @@ void hostapd_config_free_bss(struct host - os_free(conf->radius_req_attr_sqlite); - os_free(conf->rsn_preauth_interfaces); - os_free(conf->ctrl_interface); -+ os_free(conf->config_id); - os_free(conf->ca_cert); - os_free(conf->server_cert); - os_free(conf->server_cert2); -@@ -987,6 +988,7 @@ void hostapd_config_free(struct hostapd_ - - for (i = 0; i < conf->num_bss; i++) - hostapd_config_free_bss(conf->bss[i]); -+ os_free(conf->config_id); - os_free(conf->bss); - os_free(conf->supported_rates); - os_free(conf->basic_rates); ---- a/src/ap/ap_config.h -+++ b/src/ap/ap_config.h -@@ -279,6 +279,8 @@ struct hostapd_bss_config { - char vlan_bridge[IFNAMSIZ + 1]; - char wds_bridge[IFNAMSIZ + 1]; - -+ char *config_id; -+ - enum hostapd_logger_level logger_syslog_level, logger_stdout_level; - - unsigned int logger_syslog; /* module bitfield */ -@@ -938,6 +940,7 @@ struct spatial_reuse { - struct hostapd_config { - struct hostapd_bss_config **bss, *last_bss; - size_t num_bss; -+ char *config_id; - - u16 beacon_int; - int rts_threshold; ---- a/src/ap/hostapd.c -+++ b/src/ap/hostapd.c -@@ -219,6 +219,10 @@ static int hostapd_iface_conf_changed(st - { - size_t i; - -+ if (newconf->config_id != oldconf->config_id) -+ if (strcmp(newconf->config_id, oldconf->config_id)) -+ return 1; -+ - if (newconf->num_bss != oldconf->num_bss) - return 1; - -@@ -232,7 +236,7 @@ static int hostapd_iface_conf_changed(st - } - - --int hostapd_reload_config(struct hostapd_iface *iface) -+int hostapd_reload_config(struct hostapd_iface *iface, int reconf) - { - struct hapd_interfaces *interfaces = iface->interfaces; - struct hostapd_data *hapd = iface->bss[0]; -@@ -255,13 +259,16 @@ int hostapd_reload_config(struct hostapd - if (newconf == NULL) - return -1; - -- hostapd_clear_old(iface); -- - oldconf = hapd->iconf; - if (hostapd_iface_conf_changed(newconf, oldconf)) { - char *fname; - int res; - -+ if (reconf) -+ return -1; -+ -+ hostapd_clear_old(iface); -+ - wpa_printf(MSG_DEBUG, - "Configuration changes include interface/BSS modification - force full disable+enable sequence"); - fname = os_strdup(iface->config_fname); -@@ -286,6 +293,24 @@ int hostapd_reload_config(struct hostapd - wpa_printf(MSG_ERROR, - "Failed to enable interface on config reload"); - return res; -+ } else { -+ for (j = 0; j < iface->num_bss; j++) { -+ hapd = iface->bss[j]; -+ if (!hapd->config_id || strcmp(hapd->config_id, newconf->bss[j]->config_id)) { -+ hostapd_flush_old_stations(iface->bss[j], -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+#ifdef CONFIG_WEP -+ hostapd_broadcast_wep_clear(iface->bss[j]); -+#endif -+ -+#ifndef CONFIG_NO_RADIUS -+ /* TODO: update dynamic data based on changed configuration -+ * items (e.g., open/close sockets, etc.) */ -+ radius_client_flush(iface->bss[j]->radius, 0); -+#endif /* CONFIG_NO_RADIUS */ -+ wpa_printf(MSG_INFO, "bss %zu changed", j); -+ } -+ } - } - iface->conf = newconf; - -@@ -302,6 +327,12 @@ int hostapd_reload_config(struct hostapd - - for (j = 0; j < iface->num_bss; j++) { - hapd = iface->bss[j]; -+ if (hapd->config_id) { -+ os_free(hapd->config_id); -+ hapd->config_id = NULL; -+ } -+ if (newconf->bss[j]->config_id) -+ hapd->config_id = strdup(newconf->bss[j]->config_id); - hapd->iconf = newconf; - hapd->conf = newconf->bss[j]; - hostapd_reload_bss(hapd); -@@ -2397,6 +2428,10 @@ hostapd_alloc_bss_data(struct hostapd_if - hapd->iconf = conf; - hapd->conf = bss; - hapd->iface = hapd_iface; -+ if (bss && bss->config_id) -+ hapd->config_id = strdup(bss->config_id); -+ else -+ hapd->config_id = NULL; - if (conf) - hapd->driver = conf->driver; - hapd->ctrl_sock = -1; ---- a/src/ap/hostapd.h -+++ b/src/ap/hostapd.h -@@ -46,7 +46,7 @@ struct mesh_conf; - struct hostapd_iface; - - struct hapd_interfaces { -- int (*reload_config)(struct hostapd_iface *iface); -+ int (*reload_config)(struct hostapd_iface *iface, int reconf); - struct hostapd_config * (*config_read_cb)(const char *config_fname); - int (*ctrl_iface_init)(struct hostapd_data *hapd); - void (*ctrl_iface_deinit)(struct hostapd_data *hapd); -@@ -156,6 +156,7 @@ struct hostapd_data { - struct hostapd_config *iconf; - struct hostapd_bss_config *conf; - struct hostapd_ubus_bss ubus; -+ char *config_id; - int interface_added; /* virtual interface added for this BSS */ - unsigned int started:1; - unsigned int disabled:1; -@@ -604,7 +605,7 @@ struct hostapd_iface { - int hostapd_for_each_interface(struct hapd_interfaces *interfaces, - int (*cb)(struct hostapd_iface *iface, - void *ctx), void *ctx); --int hostapd_reload_config(struct hostapd_iface *iface); -+int hostapd_reload_config(struct hostapd_iface *iface, int reconf); - void hostapd_reconfig_encryption(struct hostapd_data *hapd); - struct hostapd_data * - hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, ---- a/src/drivers/driver_nl80211.c -+++ b/src/drivers/driver_nl80211.c -@@ -4820,6 +4820,9 @@ static int wpa_driver_nl80211_set_ap(voi - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", - ret, strerror(-ret)); -+ if (!bss->beacon_set) -+ ret = 0; -+ bss->beacon_set = 0; - } else { - bss->beacon_set = 1; - nl80211_set_bss(bss, params->cts_protect, params->preamble, ---- a/hostapd/ctrl_iface.c -+++ b/hostapd/ctrl_iface.c -@@ -186,7 +186,7 @@ static int hostapd_ctrl_iface_update(str - iface->interfaces->config_read_cb = hostapd_ctrl_iface_config_read; - reload_opts = txt; - -- hostapd_reload_config(iface); -+ hostapd_reload_config(iface, 0); - - iface->interfaces->config_read_cb = config_read_cb; - } ---- a/hostapd/main.c -+++ b/hostapd/main.c -@@ -317,7 +317,7 @@ static void handle_term(int sig, void *s - - static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) - { -- if (hostapd_reload_config(iface) < 0) { -+ if (hostapd_reload_config(iface, 0) < 0) { - wpa_printf(MSG_WARNING, "Failed to read new configuration " - "file - continuing with old."); - } ---- a/src/ap/wps_hostapd.c -+++ b/src/ap/wps_hostapd.c -@@ -315,7 +315,7 @@ static void wps_reload_config(void *eloo - - wpa_printf(MSG_DEBUG, "WPS: Reload configuration data"); - if (iface->interfaces == NULL || -- iface->interfaces->reload_config(iface) < 0) { -+ iface->interfaces->reload_config(iface, 1) < 0) { - wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated " - "configuration"); - } diff --git a/package/network/services/hostapd/patches/701-reload_config_inline.patch b/package/network/services/hostapd/patches/701-reload_config_inline.patch new file mode 100644 index 00000000000..3c62bf670f5 --- /dev/null +++ b/package/network/services/hostapd/patches/701-reload_config_inline.patch @@ -0,0 +1,33 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -4816,7 +4816,12 @@ struct hostapd_config * hostapd_config_r + int errors = 0; + size_t i; + +- f = fopen(fname, "r"); ++ if (!strncmp(fname, "data:", 5)) { ++ f = fmemopen((void *)(fname + 5), strlen(fname + 5), "r"); ++ fname = "<inline>"; ++ } else { ++ f = fopen(fname, "r"); ++ } + if (f == NULL) { + wpa_printf(MSG_ERROR, "Could not open configuration file '%s' " + "for reading.", fname); +--- a/wpa_supplicant/config_file.c ++++ b/wpa_supplicant/config_file.c +@@ -326,8 +326,13 @@ struct wpa_config * wpa_config_read(cons + while (cred_tail && cred_tail->next) + cred_tail = cred_tail->next; + ++ if (!strncmp(name, "data:", 5)) { ++ f = fmemopen((void *)(name + 5), strlen(name + 5), "r"); ++ name = "<inline>"; ++ } else { ++ f = fopen(name, "r"); ++ } + wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); +- f = fopen(name, "r"); + if (f == NULL) { + wpa_printf(MSG_ERROR, "Failed to open config file '%s', " + "error: %s", name, strerror(errno)); diff --git a/package/network/services/hostapd/patches/710-vlan_no_bridge.patch b/package/network/services/hostapd/patches/710-vlan_no_bridge.patch index 73db32e54a6..63d1b8a3b83 100644 --- a/package/network/services/hostapd/patches/710-vlan_no_bridge.patch +++ b/package/network/services/hostapd/patches/710-vlan_no_bridge.patch @@ -1,6 +1,6 @@ --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -115,6 +115,7 @@ struct hostapd_ssid { +@@ -121,6 +121,7 @@ struct hostapd_ssid { #define DYNAMIC_VLAN_OPTIONAL 1 #define DYNAMIC_VLAN_REQUIRED 2 int dynamic_vlan; @@ -30,7 +30,7 @@ --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -3366,6 +3366,8 @@ static int hostapd_config_fill(struct ho +@@ -3351,6 +3351,8 @@ static int hostapd_config_fill(struct ho #ifndef CONFIG_NO_VLAN } else if (os_strcmp(buf, "dynamic_vlan") == 0) { bss->ssid.dynamic_vlan = atoi(pos); diff --git a/package/network/services/hostapd/patches/711-wds_bridge_force.patch b/package/network/services/hostapd/patches/711-wds_bridge_force.patch new file mode 100644 index 00000000000..c0f2c31c448 --- /dev/null +++ b/package/network/services/hostapd/patches/711-wds_bridge_force.patch @@ -0,0 +1,22 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2318,6 +2318,8 @@ static int hostapd_config_fill(struct ho + sizeof(conf->bss[0]->iface)); + } else if (os_strcmp(buf, "bridge") == 0) { + os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); ++ if (!bss->wds_bridge[0]) ++ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge)); + } else if (os_strcmp(buf, "bridge_hairpin") == 0) { + bss->bridge_hairpin = atoi(pos); + } else if (os_strcmp(buf, "vlan_bridge") == 0) { +--- a/src/ap/ap_drv_ops.c ++++ b/src/ap/ap_drv_ops.c +@@ -348,8 +348,6 @@ int hostapd_set_wds_sta(struct hostapd_d + return -1; + if (hapd->conf->wds_bridge[0]) + bridge = hapd->conf->wds_bridge; +- else if (hapd->conf->bridge[0]) +- bridge = hapd->conf->bridge; + return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val, + bridge, ifname_wds); + } diff --git a/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch b/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch deleted file mode 100644 index 3ef19e5298c..00000000000 --- a/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5a24286ed6315e1fef755ca1970792554f59b1fc Mon Sep 17 00:00:00 2001 -From: David Bauer <mail@david-bauer.net> -Date: Wed, 26 May 2021 22:15:35 +0200 -Subject: [PATCH] ACS: fix channel 100 frequency - -Channel 100 is a valid channel to choose for 80MHz operation. However, -it's assigned to 5500 MHz, not 5550MHz. In fact, there is no channel -assigned to this frequency. - -Fix this obbvious typo to allow ACS to select channel 100 for 80 MHz -operation again. - -Fixes commit bef5eee4f7b2 ("Convert channel to frequency based selection for AP mode ACS") - -Signed-off-by: David Bauer <mail@david-bauer.net> ---- - src/ap/acs.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/src/ap/acs.c -+++ b/src/ap/acs.c -@@ -386,7 +386,7 @@ static int acs_usable_bw40_chan(const st - - static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan) - { -- const int allowed[] = { 5180, 5260, 5550, 5580, 5660, 5745, 5955, 6035, -+ const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035, - 6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675, - 6755, 6835, 6915, 6995 }; - unsigned int i; diff --git a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch index b93a0bcbef1..089c1ddc246 100644 --- a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch +++ b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch @@ -1,6 +1,6 @@ --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -2873,6 +2873,14 @@ static int hostapd_config_fill(struct ho +@@ -2848,6 +2848,14 @@ static int hostapd_config_fill(struct ho line, bss->max_num_sta, MAX_STA_COUNT); return 1; } @@ -17,20 +17,20 @@ } else if (os_strcmp(buf, "extended_key_id") == 0) { --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h -@@ -648,6 +648,7 @@ void hostapd_cleanup_cs_params(struct ho +@@ -742,6 +742,7 @@ void hostapd_cleanup_cs_params(struct ho void hostapd_periodic_iface(struct hostapd_iface *iface); int hostapd_owe_trans_get_info(struct hostapd_data *hapd); void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx); +int hostapd_check_max_sta(struct hostapd_data *hapd); - /* utils.c */ - int hostapd_register_probereq_cb(struct hostapd_data *hapd, + void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap); + void hostapd_cleanup_cca_params(struct hostapd_data *hapd); --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c -@@ -236,6 +236,30 @@ static int hostapd_iface_conf_changed(st +@@ -244,6 +244,29 @@ static int hostapd_iface_conf_changed(st + return 0; } - +static inline int hostapd_iface_num_sta(struct hostapd_iface *iface) +{ + int num_sta = 0; @@ -54,13 +54,12 @@ + + return 0; +} -+ - int hostapd_reload_config(struct hostapd_iface *iface, int reconf) + + int hostapd_reload_config(struct hostapd_iface *iface) { - struct hapd_interfaces *interfaces = iface->interfaces; --- a/src/ap/beacon.c +++ b/src/ap/beacon.c -@@ -1039,7 +1039,7 @@ void handle_probe_req(struct hostapd_dat +@@ -1252,7 +1252,7 @@ void handle_probe_req(struct hostapd_dat if (hapd->conf->no_probe_resp_if_max_sta && is_multicast_ether_addr(mgmt->da) && is_multicast_ether_addr(mgmt->bssid) && @@ -71,7 +70,7 @@ " since no room for additional STA", --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -976,6 +976,8 @@ struct hostapd_config { +@@ -1039,6 +1039,8 @@ struct hostapd_config { unsigned int track_sta_max_num; unsigned int track_sta_max_age; diff --git a/package/network/services/hostapd/patches/730-ft_iface.patch b/package/network/services/hostapd/patches/730-ft_iface.patch index 793e8e01940..0795ed15a14 100644 --- a/package/network/services/hostapd/patches/730-ft_iface.patch +++ b/package/network/services/hostapd/patches/730-ft_iface.patch @@ -1,6 +1,6 @@ --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -3031,6 +3031,8 @@ static int hostapd_config_fill(struct ho +@@ -3007,6 +3007,8 @@ static int hostapd_config_fill(struct ho wpa_printf(MSG_INFO, "Line %d: Obsolete peerkey parameter ignored", line); #ifdef CONFIG_IEEE80211R_AP @@ -11,17 +11,17 @@ hexstr2bin(pos, bss->mobility_domain, --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -277,6 +277,7 @@ struct airtime_sta_weight { +@@ -283,6 +283,7 @@ struct airtime_sta_weight { struct hostapd_bss_config { char iface[IFNAMSIZ + 1]; char bridge[IFNAMSIZ + 1]; + char ft_iface[IFNAMSIZ + 1]; char vlan_bridge[IFNAMSIZ + 1]; char wds_bridge[IFNAMSIZ + 1]; - + int bridge_hairpin; /* hairpin_mode on bridge members */ --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c -@@ -1565,8 +1565,12 @@ int hostapd_setup_wpa(struct hostapd_dat +@@ -1727,8 +1727,12 @@ int hostapd_setup_wpa(struct hostapd_dat wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { const char *ft_iface; diff --git a/package/network/services/hostapd/patches/740-snoop_iface.patch b/package/network/services/hostapd/patches/740-snoop_iface.patch new file mode 100644 index 00000000000..ce64513a421 --- /dev/null +++ b/package/network/services/hostapd/patches/740-snoop_iface.patch @@ -0,0 +1,139 @@ +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -284,6 +284,7 @@ struct hostapd_bss_config { + char iface[IFNAMSIZ + 1]; + char bridge[IFNAMSIZ + 1]; + char ft_iface[IFNAMSIZ + 1]; ++ char snoop_iface[IFNAMSIZ + 1]; + char vlan_bridge[IFNAMSIZ + 1]; + char wds_bridge[IFNAMSIZ + 1]; + int bridge_hairpin; /* hairpin_mode on bridge members */ +--- a/src/ap/x_snoop.c ++++ b/src/ap/x_snoop.c +@@ -33,28 +33,31 @@ int x_snoop_init(struct hostapd_data *ha + + hapd->x_snoop_initialized = true; + +- if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, ++ if (!conf->snoop_iface[0] && ++ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, + 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable hairpin_mode on the bridge port"); + return -1; + } + +- if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) { ++ if (!conf->snoop_iface[0] && ++ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable proxyarp on the bridge port"); + return -1; + } + + if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, +- 1)) { ++ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable accepting gratuitous ARP on the bridge"); + return -1; + } + + #ifdef CONFIG_IPV6 +- if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { ++ if (!conf->snoop_iface[0] && ++ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, NULL, 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable multicast snooping on the bridge"); + return -1; +@@ -73,8 +76,12 @@ x_snoop_get_l2_packet(struct hostapd_dat + { + struct hostapd_bss_config *conf = hapd->conf; + struct l2_packet_data *l2; ++ const char *ifname = conf->bridge; ++ ++ if (conf->snoop_iface[0]) ++ ifname = conf->snoop_iface; + +- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); ++ l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1); + if (l2 == NULL) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to initialize L2 packet processing %s", +@@ -127,9 +134,12 @@ void x_snoop_mcast_to_ucast_convert_send + + void x_snoop_deinit(struct hostapd_data *hapd) + { ++ struct hostapd_bss_config *conf = hapd->conf; ++ + if (!hapd->x_snoop_initialized) + return; +- hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0); ++ hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, ++ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 0); + hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0); + hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0); + hapd->x_snoop_initialized = false; +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2322,6 +2322,8 @@ static int hostapd_config_fill(struct ho + os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge)); + } else if (os_strcmp(buf, "bridge_hairpin") == 0) { + bss->bridge_hairpin = atoi(pos); ++ } else if (os_strcmp(buf, "snoop_iface") == 0) { ++ os_strlcpy(bss->snoop_iface, pos, sizeof(bss->snoop_iface)); + } else if (os_strcmp(buf, "vlan_bridge") == 0) { + os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); + } else if (os_strcmp(buf, "wds_bridge") == 0) { +--- a/src/ap/ap_drv_ops.h ++++ b/src/ap/ap_drv_ops.h +@@ -366,12 +366,12 @@ static inline int hostapd_drv_br_port_se + + static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd, + enum drv_br_net_param param, +- unsigned int val) ++ const char *ifname, unsigned int val) + { + if (hapd->driver == NULL || hapd->drv_priv == NULL || + hapd->driver->br_set_net_param == NULL) + return -1; +- return hapd->driver->br_set_net_param(hapd->drv_priv, param, val); ++ return hapd->driver->br_set_net_param(hapd->drv_priv, param, ifname, val); + } + + static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -4209,7 +4209,7 @@ struct wpa_driver_ops { + * Returns: 0 on success, negative (<0) on failure + */ + int (*br_set_net_param)(void *priv, enum drv_br_net_param param, +- unsigned int val); ++ const char *ifname, unsigned int val); + + /** + * get_wowlan - Get wake-on-wireless status +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -12168,7 +12168,7 @@ static const char * drv_br_net_param_str + + + static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param, +- unsigned int val) ++ const char *ifname, unsigned int val) + { + struct i802_bss *bss = priv; + char path[128]; +@@ -12194,8 +12194,11 @@ static int wpa_driver_br_set_net_param(v + return -EINVAL; + } + ++ if (!ifname) ++ ifname = bss->brname; ++ + os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s", +- ip_version, bss->brname, param_txt); ++ ip_version, ifname, param_txt); + + set_val: + if (linux_write_system_file(path, val)) diff --git a/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch b/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch new file mode 100644 index 00000000000..97c32df7044 --- /dev/null +++ b/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch @@ -0,0 +1,97 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -1604,6 +1604,8 @@ static int parse_anqp_elem(struct hostap + return 0; + } + ++#endif /* CONFIG_INTERWORKING */ ++ + + static int parse_qos_map_set(struct hostapd_bss_config *bss, + char *buf, int line) +@@ -1645,8 +1647,6 @@ static int parse_qos_map_set(struct host + return 0; + } + +-#endif /* CONFIG_INTERWORKING */ +- + + #ifdef CONFIG_HS20 + static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf, +@@ -4062,10 +4062,10 @@ static int hostapd_config_fill(struct ho + bss->gas_frag_limit = val; + } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { + bss->gas_comeback_delay = atoi(pos); ++#endif /* CONFIG_INTERWORKING */ + } else if (os_strcmp(buf, "qos_map_set") == 0) { + if (parse_qos_map_set(bss, pos, line) < 0) + return 1; +-#endif /* CONFIG_INTERWORKING */ + #ifdef CONFIG_RADIUS_TEST + } else if (os_strcmp(buf, "dump_msk_file") == 0) { + os_free(bss->dump_msk_file); +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -1486,6 +1486,7 @@ int hostapd_setup_bss(struct hostapd_dat + wpa_printf(MSG_ERROR, "GAS server initialization failed"); + return -1; + } ++#endif /* CONFIG_INTERWORKING */ + + if (conf->qos_map_set_len && + hostapd_drv_set_qos_map(hapd, conf->qos_map_set, +@@ -1493,7 +1494,6 @@ int hostapd_setup_bss(struct hostapd_dat + wpa_printf(MSG_ERROR, "Failed to initialize QoS Map"); + return -1; + } +-#endif /* CONFIG_INTERWORKING */ + + if (conf->bss_load_update_period && bss_load_update_init(hapd)) { + wpa_printf(MSG_ERROR, "BSS Load initialization failed"); +--- a/wpa_supplicant/events.c ++++ b/wpa_supplicant/events.c +@@ -2683,8 +2683,6 @@ void wnm_bss_keep_alive_deinit(struct wp + } + + +-#ifdef CONFIG_INTERWORKING +- + static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map, + size_t len) + { +@@ -2717,8 +2715,6 @@ static void interworking_process_assoc_r + } + } + +-#endif /* CONFIG_INTERWORKING */ +- + + static void wpa_supplicant_set_4addr_mode(struct wpa_supplicant *wpa_s) + { +@@ -3098,10 +3094,8 @@ static int wpa_supplicant_event_associnf + wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); + #endif /* CONFIG_WNM */ +-#ifdef CONFIG_INTERWORKING + interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); +-#endif /* CONFIG_INTERWORKING */ + if (wpa_s->hw_capab == CAPAB_VHT && + get_ie(data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP)) +--- a/src/ap/ieee802_11_shared.c ++++ b/src/ap/ieee802_11_shared.c +@@ -1116,13 +1116,11 @@ u8 * hostapd_eid_rsnxe(struct hostapd_da + u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ext_capab_ie, size_t ext_capab_ie_len) + { +-#ifdef CONFIG_INTERWORKING + /* check for QoS Map support */ + if (ext_capab_ie_len >= 5) { + if (ext_capab_ie[4] & 0x01) + sta->qos_map_enabled = 1; + } +-#endif /* CONFIG_INTERWORKING */ + + if (ext_capab_ie_len > 0) { + sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); diff --git a/package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch b/package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch new file mode 100644 index 00000000000..f5ebab70d1d --- /dev/null +++ b/package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch @@ -0,0 +1,12 @@ +--- a/src/ap/ap_drv_ops.c ++++ b/src/ap/ap_drv_ops.c +@@ -927,7 +927,8 @@ int hostapd_start_dfs_cac(struct hostapd + int hostapd_drv_set_qos_map(struct hostapd_data *hapd, + const u8 *qos_map_set, u8 qos_map_set_len) + { +- if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv) ++ if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv || ++ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)) + return 0; + return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set, + qos_map_set_len); diff --git a/package/network/services/hostapd/patches/760-dynamic_own_ip.patch b/package/network/services/hostapd/patches/760-dynamic_own_ip.patch new file mode 100644 index 00000000000..2c705a68cf0 --- /dev/null +++ b/package/network/services/hostapd/patches/760-dynamic_own_ip.patch @@ -0,0 +1,109 @@ +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -310,6 +310,7 @@ struct hostapd_bss_config { + unsigned int eap_sim_db_timeout; + int eap_server_erp; /* Whether ERP is enabled on internal EAP server */ + struct hostapd_ip_addr own_ip_addr; ++ int dynamic_own_ip_addr; + char *nas_identifier; + struct hostapd_radius_servers *radius; + int acct_interim_interval; +--- a/src/radius/radius_client.c ++++ b/src/radius/radius_client.c +@@ -163,6 +163,8 @@ struct radius_client_data { + */ + void *ctx; + ++ struct hostapd_ip_addr local_ip; ++ + /** + * conf - RADIUS client configuration (list of RADIUS servers to use) + */ +@@ -720,6 +722,30 @@ static void radius_client_list_add(struc + + + /** ++ * radius_client_send - Get local address for the RADIUS auth socket ++ * @radius: RADIUS client context from radius_client_init() ++ * @addr: pointer to store the address ++ * ++ * This function returns the local address for the connection to the RADIUS ++ * auth server. It also opens the socket if it's not available yet. ++ */ ++int radius_client_get_local_addr(struct radius_client_data *radius, ++ struct hostapd_ip_addr *addr) ++{ ++ struct hostapd_radius_servers *conf = radius->conf; ++ ++ if (conf->auth_server && radius->auth_sock < 0) ++ radius_client_init_auth(radius); ++ ++ if (radius->auth_sock < 0) ++ return -1; ++ ++ memcpy(addr, &radius->local_ip, sizeof(*addr)); ++ ++ return 0; ++} ++ ++/** + * radius_client_send - Send a RADIUS request + * @radius: RADIUS client context from radius_client_init() + * @msg: RADIUS message to be sent +@@ -1238,6 +1264,10 @@ radius_change_server(struct radius_clien + wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", + inet_ntoa(claddr.sin_addr), + ntohs(claddr.sin_port)); ++ if (auth) { ++ radius->local_ip.af = AF_INET; ++ radius->local_ip.u.v4 = claddr.sin_addr; ++ } + } + break; + #ifdef CONFIG_IPV6 +@@ -1249,6 +1279,10 @@ radius_change_server(struct radius_clien + inet_ntop(AF_INET6, &claddr6.sin6_addr, + abuf, sizeof(abuf)), + ntohs(claddr6.sin6_port)); ++ if (auth) { ++ radius->local_ip.af = AF_INET6; ++ radius->local_ip.u.v6 = claddr6.sin6_addr; ++ } + } + break; + } +--- a/src/radius/radius_client.h ++++ b/src/radius/radius_client.h +@@ -249,6 +249,8 @@ int radius_client_register(struct radius + void radius_client_set_interim_error_cb(struct radius_client_data *radius, + void (*cb)(const u8 *addr, void *ctx), + void *ctx); ++int radius_client_get_local_addr(struct radius_client_data *radius, ++ struct hostapd_ip_addr * addr); + int radius_client_send(struct radius_client_data *radius, + struct radius_msg *msg, + RadiusType msg_type, const u8 *addr); +--- a/src/ap/ieee802_1x.c ++++ b/src/ap/ieee802_1x.c +@@ -598,6 +598,10 @@ int add_common_radius_attr(struct hostap + struct hostapd_radius_attr *attr; + int len; + ++ if (hapd->conf->dynamic_own_ip_addr) ++ radius_client_get_local_addr(hapd->radius, ++ &hapd->conf->own_ip_addr); ++ + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_NAS_IP_ADDRESS) && + hapd->conf->own_ip_addr.af == AF_INET && +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2688,6 +2688,8 @@ static int hostapd_config_fill(struct ho + } else if (os_strcmp(buf, "iapp_interface") == 0) { + wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used"); + #endif /* CONFIG_IAPP */ ++ } else if (os_strcmp(buf, "dynamic_own_ip_addr") == 0) { ++ bss->dynamic_own_ip_addr = atoi(pos); + } else if (os_strcmp(buf, "own_ip_addr") == 0) { + if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { + wpa_printf(MSG_ERROR, diff --git a/package/network/services/hostapd/patches/761-shared_das_port.patch b/package/network/services/hostapd/patches/761-shared_das_port.patch new file mode 100644 index 00000000000..cbb2a1be3c4 --- /dev/null +++ b/package/network/services/hostapd/patches/761-shared_das_port.patch @@ -0,0 +1,298 @@ +--- a/src/radius/radius_das.h ++++ b/src/radius/radius_das.h +@@ -44,6 +44,7 @@ struct radius_das_attrs { + struct radius_das_conf { + int port; + const u8 *shared_secret; ++ const u8 *nas_identifier; + size_t shared_secret_len; + const struct hostapd_ip_addr *client_addr; + unsigned int time_window; +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -1423,6 +1423,7 @@ int hostapd_setup_bss(struct hostapd_dat + + os_memset(&das_conf, 0, sizeof(das_conf)); + das_conf.port = conf->radius_das_port; ++ das_conf.nas_identifier = conf->nas_identifier; + das_conf.shared_secret = conf->radius_das_shared_secret; + das_conf.shared_secret_len = + conf->radius_das_shared_secret_len; +--- a/src/radius/radius_das.c ++++ b/src/radius/radius_das.c +@@ -12,13 +12,26 @@ + #include "utils/common.h" + #include "utils/eloop.h" + #include "utils/ip_addr.h" ++#include "utils/list.h" + #include "radius.h" + #include "radius_das.h" + + +-struct radius_das_data { ++static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports); ++ ++struct radius_das_port { ++ struct dl_list list; ++ struct dl_list das_data; ++ ++ int port; + int sock; ++}; ++ ++struct radius_das_data { ++ struct dl_list list; ++ struct radius_das_port *port; + u8 *shared_secret; ++ u8 *nas_identifier; + size_t shared_secret_len; + struct hostapd_ip_addr client_addr; + unsigned int time_window; +@@ -378,56 +391,17 @@ fail: + } + + +-static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) ++static void ++radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg, ++ struct sockaddr *from, socklen_t fromlen, ++ char *abuf, int from_port) + { +- struct radius_das_data *das = eloop_ctx; +- u8 buf[1500]; +- union { +- struct sockaddr_storage ss; +- struct sockaddr_in sin; +-#ifdef CONFIG_IPV6 +- struct sockaddr_in6 sin6; +-#endif /* CONFIG_IPV6 */ +- } from; +- char abuf[50]; +- int from_port = 0; +- socklen_t fromlen; +- int len; +- struct radius_msg *msg, *reply = NULL; ++ struct radius_msg *reply = NULL; + struct radius_hdr *hdr; + struct wpabuf *rbuf; ++ struct os_time now; + u32 val; + int res; +- struct os_time now; +- +- fromlen = sizeof(from); +- len = recvfrom(sock, buf, sizeof(buf), 0, +- (struct sockaddr *) &from.ss, &fromlen); +- if (len < 0) { +- wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); +- return; +- } +- +- os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); +- from_port = ntohs(from.sin.sin_port); +- +- wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", +- len, abuf, from_port); +- if (das->client_addr.u.v4.s_addr && +- das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) { +- wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); +- return; +- } +- +- msg = radius_msg_parse(buf, len); +- if (msg == NULL) { +- wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " +- "from %s:%d failed", abuf, from_port); +- return; +- } +- +- if (wpa_debug_level <= MSG_MSGDUMP) +- radius_msg_dump(msg); + + if (radius_msg_verify_das_req(msg, das->shared_secret, + das->shared_secret_len, +@@ -494,9 +468,8 @@ static void radius_das_receive(int sock, + radius_msg_dump(reply); + + rbuf = radius_msg_get_buf(reply); +- res = sendto(das->sock, wpabuf_head(rbuf), +- wpabuf_len(rbuf), 0, +- (struct sockaddr *) &from.ss, fromlen); ++ res = sendto(das->port->sock, wpabuf_head(rbuf), ++ wpabuf_len(rbuf), 0, from, fromlen); + if (res < 0) { + wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s", + abuf, from_port, strerror(errno)); +@@ -508,6 +481,72 @@ fail: + radius_msg_free(reply); + } + ++static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++ struct radius_das_port *p = eloop_ctx; ++ struct radius_das_data *das; ++ u8 buf[1500]; ++ union { ++ struct sockaddr_storage ss; ++ struct sockaddr_in sin; ++#ifdef CONFIG_IPV6 ++ struct sockaddr_in6 sin6; ++#endif /* CONFIG_IPV6 */ ++ } from; ++ struct radius_msg *msg; ++ size_t nasid_len = 0; ++ u8 *nasid_buf = NULL; ++ char abuf[50]; ++ int from_port = 0; ++ socklen_t fromlen; ++ int found = 0; ++ int len; ++ ++ fromlen = sizeof(from); ++ len = recvfrom(sock, buf, sizeof(buf), 0, ++ (struct sockaddr *) &from.ss, &fromlen); ++ if (len < 0) { ++ wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); ++ return; ++ } ++ ++ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); ++ from_port = ntohs(from.sin.sin_port); ++ ++ msg = radius_msg_parse(buf, len); ++ if (msg == NULL) { ++ wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " ++ "from %s:%d failed", abuf, from_port); ++ return; ++ } ++ ++ wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", ++ len, abuf, from_port); ++ ++ if (wpa_debug_level <= MSG_MSGDUMP) ++ radius_msg_dump(msg); ++ ++ radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER, ++ &nasid_buf, &nasid_len, NULL); ++ dl_list_for_each(das, &p->das_data, struct radius_das_data, list) { ++ if (das->client_addr.u.v4.s_addr && ++ das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) ++ continue; ++ ++ if (das->nas_identifier && nasid_buf && ++ (nasid_len != os_strlen(das->nas_identifier) || ++ os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0)) ++ continue; ++ ++ found = 1; ++ radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss, ++ fromlen, abuf, from_port); ++ } ++ ++ if (!found) ++ wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); ++} ++ + + static int radius_das_open_socket(int port) + { +@@ -533,6 +572,49 @@ static int radius_das_open_socket(int po + } + + ++static struct radius_das_port * ++radius_das_open_port(int port) ++{ ++ struct radius_das_port *p; ++ ++ dl_list_for_each(p, &das_ports, struct radius_das_port, list) { ++ if (p->port == port) ++ return p; ++ } ++ ++ p = os_zalloc(sizeof(*p)); ++ if (p == NULL) ++ return NULL; ++ ++ dl_list_init(&p->das_data); ++ p->port = port; ++ p->sock = radius_das_open_socket(port); ++ if (p->sock < 0) ++ goto free_port; ++ ++ if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL)) ++ goto close_port; ++ ++ dl_list_add(&das_ports, &p->list); ++ ++ return p; ++ ++close_port: ++ close(p->sock); ++free_port: ++ os_free(p); ++ ++ return NULL; ++} ++ ++static void radius_das_close_port(struct radius_das_port *p) ++{ ++ dl_list_del(&p->list); ++ eloop_unregister_read_sock(p->sock); ++ close(p->sock); ++ free(p); ++} ++ + struct radius_das_data * + radius_das_init(struct radius_das_conf *conf) + { +@@ -553,6 +635,8 @@ radius_das_init(struct radius_das_conf * + das->ctx = conf->ctx; + das->disconnect = conf->disconnect; + das->coa = conf->coa; ++ if (conf->nas_identifier) ++ das->nas_identifier = os_strdup(conf->nas_identifier); + + os_memcpy(&das->client_addr, conf->client_addr, + sizeof(das->client_addr)); +@@ -565,19 +649,15 @@ radius_das_init(struct radius_das_conf * + } + das->shared_secret_len = conf->shared_secret_len; + +- das->sock = radius_das_open_socket(conf->port); +- if (das->sock < 0) { ++ das->port = radius_das_open_port(conf->port); ++ if (!das->port) { + wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS " + "DAS"); + radius_das_deinit(das); + return NULL; + } + +- if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL)) +- { +- radius_das_deinit(das); +- return NULL; +- } ++ dl_list_add(&das->port->das_data, &das->list); + + return das; + } +@@ -588,11 +668,14 @@ void radius_das_deinit(struct radius_das + if (das == NULL) + return; + +- if (das->sock >= 0) { +- eloop_unregister_read_sock(das->sock); +- close(das->sock); ++ if (das->port) { ++ dl_list_del(&das->list); ++ ++ if (dl_list_empty(&das->port->das_data)) ++ radius_das_close_port(das->port); + } + ++ os_free(das->nas_identifier); + os_free(das->shared_secret); + os_free(das); + } diff --git a/package/network/services/hostapd/patches/770-radius_server.patch b/package/network/services/hostapd/patches/770-radius_server.patch new file mode 100644 index 00000000000..8837a26257b --- /dev/null +++ b/package/network/services/hostapd/patches/770-radius_server.patch @@ -0,0 +1,154 @@ +--- a/hostapd/Makefile ++++ b/hostapd/Makefile +@@ -63,6 +63,10 @@ endif + OBJS += main.o + OBJS += config_file.o + ++ifdef CONFIG_RADIUS_SERVER ++OBJS += radius.o ++endif ++ + OBJS += ../src/ap/hostapd.o + OBJS += ../src/ap/wpa_auth_glue.o + OBJS += ../src/ap/drv_callbacks.o +--- a/hostapd/main.c ++++ b/hostapd/main.c +@@ -40,6 +40,7 @@ struct hapd_global { + + static struct hapd_global global; + ++extern int radius_main(int argc, char **argv); + + #ifndef CONFIG_NO_HOSTAPD_LOGGER + static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, +@@ -771,6 +772,11 @@ int main(int argc, char *argv[]) + if (os_program_init()) + return -1; + ++#ifdef RADIUS_SERVER ++ if (strstr(argv[0], "radius")) ++ return radius_main(argc, argv); ++#endif ++ + os_memset(&interfaces, 0, sizeof(interfaces)); + interfaces.reload_config = hostapd_reload_config; + interfaces.config_read_cb = hostapd_config_read; +--- a/src/radius/radius_server.c ++++ b/src/radius/radius_server.c +@@ -63,6 +63,12 @@ struct radius_server_counters { + u32 unknown_acct_types; + }; + ++struct radius_accept_attr { ++ u8 type; ++ u16 len; ++ void *data; ++}; ++ + /** + * struct radius_session - Internal RADIUS server data for a session + */ +@@ -90,7 +96,7 @@ struct radius_session { + unsigned int macacl:1; + unsigned int t_c_filtering:1; + +- struct hostapd_radius_attr *accept_attr; ++ struct radius_accept_attr *accept_attr; + + u32 t_c_timestamp; /* Last read T&C timestamp from user DB */ + }; +@@ -394,6 +400,7 @@ static void radius_server_session_free(s + radius_msg_free(sess->last_reply); + os_free(sess->username); + os_free(sess->nas_ip); ++ os_free(sess->accept_attr); + os_free(sess); + data->num_sess--; + } +@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius + } + #endif /* CONFIG_ERP */ + ++static struct radius_accept_attr * ++radius_server_copy_attr(const struct hostapd_radius_attr *data) ++{ ++ const struct hostapd_radius_attr *attr; ++ struct radius_accept_attr *attr_new; ++ size_t data_size = 0; ++ void *data_buf; ++ int n_attr = 1; ++ ++ for (attr = data; attr; attr = attr->next) { ++ n_attr++; ++ data_size += wpabuf_len(attr->val); ++ } ++ ++ attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size); ++ if (!attr_new) ++ return NULL; ++ ++ data_buf = &attr_new[n_attr]; ++ for (n_attr = 0, attr = data; attr; attr = attr->next) { ++ struct radius_accept_attr *cur = &attr_new[n_attr++]; ++ ++ cur->type = attr->type; ++ cur->len = wpabuf_len(attr->val); ++ cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len); ++ data_buf += cur->len; ++ } ++ ++ return attr_new; ++} + + static struct radius_session * + radius_server_get_new_session(struct radius_server_data *data, +@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad + eap_user_free(tmp); + return NULL; + } +- sess->accept_attr = tmp->accept_attr; ++ sess->accept_attr = radius_server_copy_attr(tmp->accept_attr); + sess->macacl = tmp->macacl; + eap_user_free(tmp); + +@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad + } + + if (code == RADIUS_CODE_ACCESS_ACCEPT) { +- struct hostapd_radius_attr *attr; +- for (attr = sess->accept_attr; attr; attr = attr->next) { +- if (!radius_msg_add_attr(msg, attr->type, +- wpabuf_head(attr->val), +- wpabuf_len(attr->val))) { ++ struct radius_accept_attr *attr; ++ for (attr = sess->accept_attr; attr->data; attr++) { ++ if (!radius_msg_add_attr(msg, attr->type, attr->data, ++ attr->len)) { + wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); + radius_msg_free(msg); + return NULL; +@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve + } + + if (code == RADIUS_CODE_ACCESS_ACCEPT) { +- struct hostapd_radius_attr *attr; +- for (attr = sess->accept_attr; attr; attr = attr->next) { +- if (!radius_msg_add_attr(msg, attr->type, +- wpabuf_head(attr->val), +- wpabuf_len(attr->val))) { ++ struct radius_accept_attr *attr; ++ for (attr = sess->accept_attr; attr->data; attr++) { ++ if (!radius_msg_add_attr(msg, attr->type, attr->data, ++ attr->len)) { + wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); + radius_msg_free(msg); + return NULL; +@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo + ret = data->get_eap_user(data->conf_ctx, identity, identity_len, + phase2, user); + if (ret == 0 && user) { +- sess->accept_attr = user->accept_attr; ++ sess->accept_attr = radius_server_copy_attr(user->accept_attr); + sess->remediation = user->remediation; + sess->macacl = user->macacl; + sess->t_c_timestamp = user->t_c_timestamp; diff --git a/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch b/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch new file mode 100644 index 00000000000..5809a3b7e81 --- /dev/null +++ b/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch @@ -0,0 +1,33 @@ +From f0e9f5aab52b3eab85d28338cc996972ced4c39c Mon Sep 17 00:00:00 2001 +From: David Bauer <mail@david-bauer.net> +Date: Tue, 17 May 2022 23:07:59 +0200 +Subject: [PATCH] ctrl: make WNM_AP functions dependant on CONFIG_AP + +This fixes linking errors found when compiling wpa_supplicant with +CONFIG_WNM_AP enabled but CONFIG_AP disabled. + +Signed-off-by: David Bauer <mail@david-bauer.net> +--- + wpa_supplicant/ctrl_iface.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/wpa_supplicant/ctrl_iface.c ++++ b/wpa_supplicant/ctrl_iface.c +@@ -12763,7 +12763,7 @@ char * wpa_supplicant_ctrl_iface_process + if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) + reply_len = -1; + #endif /* CONFIG_WNM */ +-#ifdef CONFIG_WNM_AP ++#if defined(CONFIG_AP) && defined(CONFIG_WNM_AP) + } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { + if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18)) + reply_len = -1; +@@ -12773,7 +12773,7 @@ char * wpa_supplicant_ctrl_iface_process + } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { + if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11)) + reply_len = -1; +-#endif /* CONFIG_WNM_AP */ ++#endif /* CONFIG_AP && CONFIG_WNM_AP */ + } else if (os_strcmp(buf, "FLUSH") == 0) { + wpa_supplicant_ctrl_iface_flush(wpa_s); + } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { diff --git a/package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch b/package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch new file mode 100644 index 00000000000..097d62abc01 --- /dev/null +++ b/package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch @@ -0,0 +1,63 @@ +From 26cd9bafc1d25e602952ee86cd2a5b8c3a995490 Mon Sep 17 00:00:00 2001 +From: Stijn Tintel <stijn@linux-ipv6.be> +Date: Fri, 28 Jul 2023 16:27:47 +0300 +Subject: [PATCH] Revert "Do prune_association only after the STA is + authorized" + +Commit e978072baaca ("Do prune_association only after the STA is +authorized") causes issues when an STA roams from one interface to +another interface on the same PHY. The mt7915 driver is not able to +handle this properly. While the commits fixes a DoS, there are other +devices and drivers with the same limitation, so revert to the orginal +behavior for now, until we have a better solution in place. + +Ref: https://github.com/openwrt/openwrt/issues/13156 +Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be> +--- + src/ap/hostapd.c | 14 +++++++++++--- + src/ap/sta_info.c | 3 --- + 2 files changed, 11 insertions(+), 6 deletions(-) + +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -3564,6 +3564,8 @@ int hostapd_remove_iface(struct hapd_int + void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc) + { ++ int mld_assoc_link_id = -1; ++ + if (hapd->tkip_countermeasures) { + hostapd_drv_sta_deauth(hapd, sta->addr, + WLAN_REASON_MICHAEL_MIC_FAILURE); +@@ -3571,10 +3573,16 @@ void hostapd_new_assoc_sta(struct hostap + } + + #ifdef CONFIG_IEEE80211BE +- if (hapd->conf->mld_ap && sta->mld_info.mld_sta && +- sta->mld_assoc_link_id != hapd->mld_link_id) +- return; ++ if (hapd->conf->mld_ap && sta->mld_info.mld_sta) { ++ if (sta->mld_assoc_link_id == hapd->mld_link_id) { ++ mld_assoc_link_id = sta->mld_assoc_link_id; ++ } else { ++ return; ++ } ++ } + #endif /* CONFIG_IEEE80211BE */ ++ if (mld_assoc_link_id != -2) ++ hostapd_prune_associations(hapd, sta->addr, mld_assoc_link_id); + + ap_sta_clear_disconnect_timeouts(hapd, sta); + sta->post_csa_sa_query = 0; +--- a/src/ap/sta_info.c ++++ b/src/ap/sta_info.c +@@ -1318,9 +1318,6 @@ void ap_sta_set_authorized(struct hostap + mld_assoc_link_id = -2; + } + #endif /* CONFIG_IEEE80211BE */ +- if (mld_assoc_link_id != -2) +- hostapd_prune_associations(hapd, sta->addr, +- mld_assoc_link_id); + sta->flags |= WLAN_STA_AUTHORIZED; + } else { + sta->flags &= ~WLAN_STA_AUTHORIZED; diff --git a/package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch b/package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch new file mode 100644 index 00000000000..c7b595da57d --- /dev/null +++ b/package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch @@ -0,0 +1,62 @@ +From: David Bauer <mail@david-bauer.net> +To: hostap@lists.infradead.org +Cc: =?utf-8?q?=C3=89tienne_Morice?= <neon.emorice@mail.com> +Subject: [PATCH] nl80211: add extra-ies only if allowed by driver +Date: Sun, 30 Jan 2022 20:22:00 +0100 +Message-Id: <20220130192200.10883-1-mail@david-bauer.net> +List-Id: <hostap.lists.infradead.org> + +Upgrading wpa_supplicant from 2.9 to 2.10 breaks broadcom-wl +based adapters. The reason for it is hostapd tries to install additional +IEs for scanning while the driver does not support this. + +The kernel indicates the maximum number of bytes for additional scan IEs +using the NL80211_ATTR_MAX_SCAN_IE_LEN attribute. Save this value and +only add additional scan IEs in case the driver can accommodate these +additional IEs. + +Reported-by: Étienne Morice <neon.emorice@mail.com> +Tested-by: Étienne Morice <neon.emorice@mail.com> +Signed-off-by: David Bauer <mail@david-bauer.net> +--- + src/drivers/driver.h | 3 +++ + src/drivers/driver_nl80211_capa.c | 4 ++++ + src/drivers/driver_nl80211_scan.c | 2 +- + 3 files changed, 8 insertions(+), 1 deletion(-) + +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -2283,6 +2283,9 @@ struct wpa_driver_capa { + /** Maximum number of iterations in a single scan plan */ + u32 max_sched_scan_plan_iterations; + ++ /** Maximum number of extra IE bytes for scans */ ++ u16 max_scan_ie_len; ++ + /** Whether sched_scan (offloaded scanning) is supported */ + int sched_scan_supported; + +--- a/src/drivers/driver_nl80211_capa.c ++++ b/src/drivers/driver_nl80211_capa.c +@@ -949,6 +949,10 @@ static int wiphy_info_handler(struct nl_ + nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]); + } + ++ if (tb[NL80211_ATTR_MAX_SCAN_IE_LEN]) ++ capa->max_scan_ie_len = ++ nla_get_u16(tb[NL80211_ATTR_MAX_SCAN_IE_LEN]); ++ + if (tb[NL80211_ATTR_MAX_MATCH_SETS]) + capa->max_match_sets = + nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); +--- a/src/drivers/driver_nl80211_scan.c ++++ b/src/drivers/driver_nl80211_scan.c +@@ -222,7 +222,7 @@ nl80211_scan_common(struct i802_bss *bss + wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested"); + } + +- if (params->extra_ies) { ++ if (params->extra_ies && drv->capa.max_scan_ie_len >= params->extra_ies_len) { + wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", + params->extra_ies, params->extra_ies_len); + if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len, diff --git a/package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch b/package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch new file mode 100644 index 00000000000..948c51b196b --- /dev/null +++ b/package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch @@ -0,0 +1,25 @@ +From 7a733993211ad46cf3032038c1e7e6bdc2322336 Mon Sep 17 00:00:00 2001 +From: Michael-CY Lee <michael-cy.lee@mediatek.com> +Date: Tue, 5 Sep 2023 09:43:25 +0800 +Subject: [PATCH] ACS: Fix typo in bw_40 frequency array + +The range for the 5 GHz channel 118 was encoded with an incorrect +channel number. + +Fixes: ed8e13decc71 (ACS: Extract bw40/80/160 freqs out of acs_usable_bwXXX_chan()) +Signed-off-by: Michael Lee <michael-cy.lee@mediatek.com> +--- + src/ap/acs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/src/ap/acs.c ++++ b/src/ap/acs.c +@@ -256,7 +256,7 @@ struct bw_item { + static const struct bw_item bw_40[] = { + { 5180, 5200, 38 }, { 5220, 5240, 46 }, { 5260, 5280, 54 }, + { 5300, 5320, 62 }, { 5500, 5520, 102 }, { 5540, 5560, 110 }, +- { 5580, 5600, 110 }, { 5620, 5640, 126}, { 5660, 5680, 134 }, ++ { 5580, 5600, 118 }, { 5620, 5640, 126 }, { 5660, 5680, 134 }, + { 5700, 5720, 142 }, { 5745, 5765, 151 }, { 5785, 5805, 159 }, + { 5825, 5845, 167 }, { 5865, 5885, 175 }, + { 5955, 5975, 3 }, { 5995, 6015, 11 }, { 6035, 6055, 19 }, |
