]> git.ipfire.org Git - network.git/commitdiff
wireless-ap: Automatically enable all supported ciphers
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 30 Mar 2019 10:27:50 +0000 (11:27 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 30 Mar 2019 10:27:50 +0000 (11:27 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/functions/functions.hostapd
src/functions/functions.phy
src/libnetwork/libnetwork.sym
src/libnetwork/network/phy.h
src/libnetwork/phy.c
src/utils/.gitignore
src/utils/network-phy-list-ciphers.c [new file with mode: 0644]

index 0139f95e82e0eb268e96742cc637f8cc8b46a670..1b5e7e92ec03f40d90570262dd03cec23e187519 100644 (file)
@@ -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
 
index 737bd1a1bbb4b948d790023c490d49726f65414e..6111457f9894846df4a0a249b9fa10e0e7ad4e5f 100644 (file)
@@ -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
+}
index 120117ccf6040cddc2c879ae395000016ff90106..c06389c8cc5e166bc47c8f136b1d1cd67a7d4191 100644 (file)
@@ -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
index 593c4a2b7fe9898cbe72b691d25b13268a2d1722..034d43f73f3f1a6f49736a8a040773c783ab6b18 100644 (file)
@@ -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:
-        *;
+       *;
 };
index 9059680447372e55fa0fe8cef51535989b7ddd9d..bc6dafb4c30318be444627c62f0d44306fdecf17 100644 (file)
@@ -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)
 
index 0bf9c81b844aab87c77ffadae0c1c834309e49bd..e3f2aad934776be913623c5b2664ad6571a59872 100644 (file)
@@ -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;
 }
index 11cf3b699118f5d852951a1e7f91aa632bd9335d..df712dc33ebee4cdb9670169afcd50a5f486dc9e 100644 (file)
@@ -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 (file)
index 0000000..0132c0c
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <network/libnetwork.h>
+#include <network/logging.h>
+#include <network/phy.h>
+
+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;
+}