From: Michael Tremer Date: Sat, 30 Mar 2019 10:27:50 +0000 (+0100) Subject: wireless-ap: Automatically enable all supported ciphers X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2e4e3c88ba2543e5bf4bf3f92977990c281a00bb;p=network.git wireless-ap: Automatically enable all supported ciphers Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 0139f95e..1b5e7e92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -301,6 +301,7 @@ EXTRA_DIST += \ util_PROGRAMS = \ src/utils/network-phy-list-channels \ + src/utils/network-phy-list-ciphers \ src/utils/network-phy-list-ht-caps \ src/utils/network-phy-list-vht-caps @@ -310,6 +311,12 @@ src_utils_network_phy_list_channels_SOURCES = \ src_utils_network_phy_list_channels_LDADD = \ src/libnetwork.la +src_utils_network_phy_list_ciphers_SOURCES = \ + src/utils/network-phy-list-ciphers.c + +src_utils_network_phy_list_ciphers_LDADD = \ + src/libnetwork.la + src_utils_network_phy_list_ht_caps_SOURCES = \ src/utils/network-phy-list-ht-caps.c diff --git a/src/functions/functions.hostapd b/src/functions/functions.hostapd index 737bd1a1..6111457f 100644 --- a/src/functions/functions.hostapd +++ b/src/functions/functions.hostapd @@ -23,6 +23,19 @@ HOSTAPD_CONTROL_INTERFACE_DIR="/run/hostapd/ctrl" HOSTAPD_SUPPORTED_MODES="802.11a 802.11a/n 802.11ac 802.11g 802.11g/n" +HOSTAPD_SUPPORTED_PAIRWISE_CIPHERS=( + "GCMP-256" # Galois/counter mode protocol with 256 bit key + "CCMP-256" # AES in Counter mode with CBC-MAC with 256 bit key + "GCMP-128" # Galois/counter mode protocol with 128 bit key + "CCMP-128" # AES in Counter mode with CBC-MAC with 128 bit key +) + +# This must be supported by all stations on the network and therefore +# can effectively only be CCMP +HOSTAPD_SUPPORTED_GROUP_CIPHERS=( + "CCMP-128" +) + hostapd_config_write() { local device=${1} assert isset device @@ -33,6 +46,16 @@ hostapd_config_write() { # Shift the device and file argument. shift 2 + # Device must exist + if ! device_exists "${device}"; then + error "Cannot write hostapd configuration for non-existant device: ${device}" + return ${EXIT_ERROR} + fi + + # Get the phy for device + local phy="$(device_get_phy "${device}")" + assert isset phy + local broadcast_ssid local channel local channel_bandwidth @@ -201,6 +224,25 @@ hostapd_config_write() { ;; esac + # Cryptography + local cipher + + # Get all supported pairwise ciphers + local pairwise_ciphers=() + for cipher in ${HOSTAPD_SUPPORTED_PAIRWISE_CIPHERS[*]}; do + if phy_supports_cipher "${phy}" "${cipher}"; then + pairwise_ciphers+=( "$(hostapd_cipher_name "${cipher}")" ) + fi + done + + # Get all supported group ciphers + local group_ciphers=() + for cipher in ${HOSTAPD_SUPPORTED_GROUP_CIPHERS[*]}; do + if phy_supports_cipher "${phy}" "${cipher}"; then + group_ciphers+=( "$(hostapd_cipher_name "${cipher}")" ) + fi + done + # Create configuration directory. local config_dir=$(dirname ${file}) mkdir -p ${HOSTAPD_CONTROL_INTERFACE_DIR} ${config_dir} 2>/dev/null @@ -372,8 +414,9 @@ hostapd_config_write() { print "wpa=${encryption_mode}" print "wpa_passphrase=${key}" print "wpa_key_mgmt=WPA-PSK" - print "wpa_pairwise=TKIP" - print "rsn_pairwise=CCMP" + print "wpa_pairwise=${pairwise_ciphers[*]}" + print "rsn_pairwise=${pairwise_ciphers[*]}" + print "group_cipher=${group_ciphers[*]}" print ) >> ${file} fi @@ -407,3 +450,21 @@ hostapd_stop() { service_stop "hostapd@${device}.service" } + +hostapd_cipher_name() { + local cipher="${1}" + + case "${cipher}" in + CCMP-128) + print "CCMP" + ;; + + GCMP-128) + print "GCMP" + ;; + + *) + print "${cipher}" + ;; + esac +} diff --git a/src/functions/functions.phy b/src/functions/functions.phy index 120117cc..c06389c8 100644 --- a/src/functions/functions.phy +++ b/src/functions/functions.phy @@ -208,6 +208,23 @@ phy_supports_channel() { return ${EXIT_FALSE} } +phy_list_ciphers() { + local phy="${1}" + assert isset phy + + network-phy-list-ciphers "${phy}" +} + +phy_supports_cipher() { + local phy="${1}" + assert isset phy + + local cipher="${2}" + assert isset cipher + + list_match "${cipher}" $(phy_list_ciphers "${phy}") +} + __phy_list_ht_capabilities() { local phy="${1}" assert isset phy diff --git a/src/libnetwork/libnetwork.sym b/src/libnetwork/libnetwork.sym index 593c4a2b..034d43f7 100644 --- a/src/libnetwork/libnetwork.sym +++ b/src/libnetwork/libnetwork.sym @@ -1,21 +1,24 @@ LIBNETWORK_0 { global: - network_interface_get_name; - network_interface_new; - network_interface_ref; - network_interface_unref; - network_new; - network_phy_has_ht_capability; - network_phy_has_vht_capability; - network_phy_list_channels; - network_phy_list_ht_capabilities; - network_phy_list_vht_capabilities; - network_phy_new; - network_phy_ref; - network_phy_unref; - network_ref; - network_unref; - network_version; + network_interface_get_name; + network_interface_new; + network_interface_ref; + network_interface_unref; + network_new; + network_phy_get_cipher_string; + network_phy_has_ht_capability; + network_phy_has_vht_capability; + network_phy_list_channels; + network_phy_list_ciphers; + network_phy_list_ht_capabilities; + network_phy_list_vht_capabilities; + network_phy_supports_cipher; + network_phy_new; + network_phy_ref; + network_phy_unref; + network_ref; + network_unref; + network_version; local: - *; + *; }; diff --git a/src/libnetwork/network/phy.h b/src/libnetwork/network/phy.h index 90596804..bc6dafb4 100644 --- a/src/libnetwork/network/phy.h +++ b/src/libnetwork/network/phy.h @@ -30,6 +30,25 @@ int network_phy_new(struct network_ctx*, struct network_phy** phy, const char* n struct network_phy* network_phy_ref(struct network_phy* phy); struct network_phy* network_phy_unref(struct network_phy* phy); +enum network_phy_ciphers { + NETWORK_PHY_CIPHER_WEP40 = (1 << 0), + NETWORK_PHY_CIPHER_TKIP = (1 << 1), + NETWORK_PHY_CIPHER_CCMP128 = (1 << 2), + NETWORK_PHY_CIPHER_WEP104 = (1 << 3), + NETWORK_PHY_CIPHER_CMAC128 = (1 << 4), + NETWORK_PHY_CIPHER_GCMP128 = (1 << 5), + NETWORK_PHY_CIPHER_GCMP256 = (1 << 6), + NETWORK_PHY_CIPHER_CCMP256 = (1 << 7), + NETWORK_PHY_CIPHER_GMAC128 = (1 << 8), + NETWORK_PHY_CIPHER_GMAC256 = (1 << 9), + NETWORK_PHY_CIPHER_CMAC256 = (1 << 10), + NETWORK_PHY_CIPHER_WPISMS4 = (1 << 11), +}; + +const char* network_phy_get_cipher_string(const enum network_phy_ciphers cipher); +int network_phy_supports_cipher(struct network_phy* phy, const enum network_phy_ciphers cipher); +char* network_phy_list_ciphers(struct network_phy* phy); + enum network_phy_ht_caps { NETWORK_PHY_HT_CAP_RX_LDPC = (1 << 0), NETWORK_PHY_HT_CAP_HT40 = (1 << 1), @@ -81,6 +100,9 @@ char* network_phy_list_ht_capabilities(struct network_phy* phy); struct nl_msg* network_phy_make_netlink_message(struct network_phy* phy, enum nl80211_commands cmd, int flags); +#define foreach_cipher(cipher) \ + for(enum network_phy_ciphers cipher = NETWORK_PHY_CIPHER_WEP40; cipher <= NETWORK_PHY_CIPHER_WPISMS4; cipher <<= 1) + #define foreach_vht_cap(cap) \ for(int cap = NETWORK_PHY_VHT_CAP_VHT160; cap <= NETWORK_PHY_VHT_CAP_TX_ANTENNA_PATTERN; cap <<= 1) diff --git a/src/libnetwork/phy.c b/src/libnetwork/phy.c index 0bf9c81b..e3f2aad9 100644 --- a/src/libnetwork/phy.c +++ b/src/libnetwork/phy.c @@ -52,6 +52,7 @@ struct network_phy { TAILQ_HEAD(head, network_phy_channel) channels; + enum network_phy_ciphers ciphers; ssize_t max_mpdu_length; unsigned int vht_caps; unsigned int ht_caps; @@ -80,6 +81,81 @@ static int phy_get_index(const char* name) { return atoi(index); } +static void phy_parse_ciphers(struct network_phy* phy, __u32* ciphers, int num) { + enum network_phy_ciphers cipher; + + // Reset value + phy->ciphers = 0; + + for (int i = 0; i < num; i++) { + switch (ciphers[i]) { + case 0x000fac01: + cipher = NETWORK_PHY_CIPHER_WEP40; + break; + + case 0x000fac02: + cipher = NETWORK_PHY_CIPHER_TKIP; + break; + + case 0x000fac04: + cipher = NETWORK_PHY_CIPHER_CCMP128; + break; + + case 0x000fac05: + cipher = NETWORK_PHY_CIPHER_WEP104; + break; + + case 0x000fac06: + cipher = NETWORK_PHY_CIPHER_CMAC128; + break; + + case 0x000fac08: + cipher = NETWORK_PHY_CIPHER_GCMP128; + break; + + case 0x000fac09: + cipher = NETWORK_PHY_CIPHER_GCMP256; + break; + + /* + I have no idea what these are. My card reports them but + I could not find out anything about them. + */ + case 0x000fac0a: + case 0x000fac0b: + case 0x000fac0c: + case 0x000fac0d: + continue; + + case 0x000fac10: + cipher = NETWORK_PHY_CIPHER_CCMP256; + break; + + case 0x000fac11: + cipher = NETWORK_PHY_CIPHER_GMAC128; + break; + + case 0x000fac12: + cipher = NETWORK_PHY_CIPHER_GMAC256; + break; + + case 0x000fac13: + cipher = NETWORK_PHY_CIPHER_CMAC256; + break; + + case 0x00147201: + cipher = NETWORK_PHY_CIPHER_WPISMS4; + break; + + default: + ERROR(phy->ctx, "Unknown cipher found: %x\n", ciphers[i]); + continue; + } + + phy->ciphers |= cipher; + } +} + static void phy_parse_vht_capabilities(struct network_phy* phy, __u32 caps) { // Max MPDU length switch (caps & 0x3) { @@ -325,6 +401,13 @@ static int phy_parse_info(struct nl_msg* msg, void* data) { nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + // Ciphers + if (attrs[NL80211_ATTR_CIPHER_SUITES]) { + int num = nla_len(attrs[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32); + __u32* ciphers = nla_data(attrs[NL80211_ATTR_CIPHER_SUITES]); + phy_parse_ciphers(phy, ciphers, num); + } + if (attrs[NL80211_ATTR_WIPHY_BANDS]) { struct nlattr* nl_band; int i; @@ -464,6 +547,72 @@ nla_put_failure: return NULL; } +NETWORK_EXPORT const char* network_phy_get_cipher_string(const enum network_phy_ciphers cipher) { + switch (cipher) { + case NETWORK_PHY_CIPHER_WEP40: + return "WEP40"; + + case NETWORK_PHY_CIPHER_TKIP: + return "TKIP"; + + case NETWORK_PHY_CIPHER_CCMP128: + return "CCMP-128"; + + case NETWORK_PHY_CIPHER_WEP104: + return "WEP-104"; + + case NETWORK_PHY_CIPHER_CMAC128: + return "CMAC-128"; + + case NETWORK_PHY_CIPHER_GCMP128: + return "GCMP-128"; + + case NETWORK_PHY_CIPHER_GCMP256: + return "GCMP-256"; + + case NETWORK_PHY_CIPHER_CCMP256: + return "CCMP-256"; + + case NETWORK_PHY_CIPHER_GMAC128: + return "GMAC-128"; + + case NETWORK_PHY_CIPHER_GMAC256: + return "GMAC-256"; + + case NETWORK_PHY_CIPHER_CMAC256: + return "CMAC-256"; + + case NETWORK_PHY_CIPHER_WPISMS4: + return "WPI-SMS4"; + } + + return NULL; +} + +NETWORK_EXPORT int network_phy_supports_cipher(struct network_phy* phy, const enum network_phy_ciphers cipher) { + return phy->ciphers & cipher; +} + +NETWORK_EXPORT char* network_phy_list_ciphers(struct network_phy* phy) { + char* buffer = NULL; + + foreach_cipher(cipher) { + if (network_phy_supports_cipher(phy, cipher)) { + const char* s = network_phy_get_cipher_string(cipher); + + if (!s) + continue; + + if (buffer) + asprintf(&buffer, "%s %s", buffer, s); + else + asprintf(&buffer, "%s", s); + } + } + + return buffer; +} + NETWORK_EXPORT int network_phy_has_vht_capability(struct network_phy* phy, const enum network_phy_vht_caps cap) { return phy->vht_caps & cap; } diff --git a/src/utils/.gitignore b/src/utils/.gitignore index 11cf3b69..df712dc3 100644 --- a/src/utils/.gitignore +++ b/src/utils/.gitignore @@ -1,3 +1,4 @@ /network-phy-list-channels +/network-phy-list-ciphers /network-phy-list-ht-caps /network-phy-list-vht-caps diff --git a/src/utils/network-phy-list-ciphers.c b/src/utils/network-phy-list-ciphers.c new file mode 100644 index 00000000..0132c0cf --- /dev/null +++ b/src/utils/network-phy-list-ciphers.c @@ -0,0 +1,61 @@ +/*############################################################################# +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2019 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include + +int main(int argc, char** argv) { + struct network_ctx* ctx = NULL; + struct network_phy* phy = NULL; + int r; + + if (argc < 2) { + fprintf(stderr, "No enough arguments\n"); + r = 2; + goto END; + } + + // Initialise context + r = network_new(&ctx); + if (r) + return r; + + r = network_phy_new(ctx, &phy, argv[1]); + if (r) { + fprintf(stderr, "Could not find %s\n", argv[1]); + goto END; + } + + // Print all supported ciphers + char* ciphers = network_phy_list_ciphers(phy); + if (ciphers && *ciphers) { + printf("%s\n", ciphers); + free(ciphers); + } + +END: + network_phy_unref(phy); + network_unref(ctx); + return r; +}