summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2020-11-03 17:20:10 +0100
committerChristian Poessinger <christian@poessinger.com>2020-11-03 17:20:10 +0100
commit28d9061ea913741980972b31c59d819b11bd5c8e (patch)
treef30e7e2b6bb71c0cb50cba55d529e1c952c44d9f
parentf8a4314503072af90d8a4ab443898be7c73f3895 (diff)
downloadvyos-1x-28d9061ea913741980972b31c59d819b11bd5c8e.tar.gz
vyos-1x-28d9061ea913741980972b31c59d819b11bd5c8e.zip
wireless: T3034: add WPA3 support
-rw-r--r--data/templates/wifi/hostapd.conf.tmpl22
-rw-r--r--data/templates/wifi/wpa_supplicant.conf.tmpl70
-rw-r--r--interface-definitions/interfaces-wireless.xml.in4
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wireless.py63
4 files changed, 152 insertions, 7 deletions
diff --git a/data/templates/wifi/hostapd.conf.tmpl b/data/templates/wifi/hostapd.conf.tmpl
index 409c9d3bc..95837da95 100644
--- a/data/templates/wifi/hostapd.conf.tmpl
+++ b/data/templates/wifi/hostapd.conf.tmpl
@@ -538,7 +538,7 @@ wep_key{{ loop.index -1 }}={{ security.wep.key }}
{% if security.wpa.mode is defined %}
{% if security.wpa.mode == 'wpa+wpa2' %}
wpa=3
-{% elif security.wpa.mode == 'wpa2' %}
+{% elif security.wpa.mode == 'wpa2' or security.wpa.mode == 'wpa3' %}
wpa=2
{% elif security.wpa.mode == 'wpa' %}
wpa=1
@@ -598,7 +598,15 @@ wpa_passphrase={{ security.wpa.passphrase }}
# added to enable SHA256-based stronger algorithms.
# WPA-PSK = WPA-Personal / WPA2-Personal
# WPA-PSK-SHA256 = WPA2-Personal using SHA256
-wpa_key_mgmt=WPA-PSK
+# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
+# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
+# SAE = SAE (WPA3-Personal)
+# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
+{% if security.wpa.mode is defined and security.wpa.mode == 'wpa3' %}
+wpa_key_mgmt=SAE
+{% else %}
+wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256
+{% endif %}
{% elif security.wpa.radius is defined %}
##### IEEE 802.1X-2004 related configuration ##################################
@@ -608,9 +616,17 @@ ieee8021x=1
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
+# WPA-PSK = WPA-Personal / WPA2-Personal
+# WPA-PSK-SHA256 = WPA2-Personal using SHA256
# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
-wpa_key_mgmt=WPA-EAP
+# SAE = SAE (WPA3-Personal)
+# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
+{% if security.wpa.mode is defined and security.wpa.mode == 'wpa3' %}
+wpa_key_mgmt=WPA-EAP-SUITE-B-192
+{% else %}
+wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
+{% endif %}
{% if security.wpa.radius.server is defined %}
# RADIUS client forced local IP address for the access point
diff --git a/data/templates/wifi/wpa_supplicant.conf.tmpl b/data/templates/wifi/wpa_supplicant.conf.tmpl
index f84892dc0..20b4f7976 100644
--- a/data/templates/wifi/wpa_supplicant.conf.tmpl
+++ b/data/templates/wifi/wpa_supplicant.conf.tmpl
@@ -4,10 +4,78 @@
# https://w1.fi/cgit/hostap/plain/wpa_supplicant/wpa_supplicant.conf
network={
+ # ssid: SSID (mandatory); network name in one of the optional formats:
+ # - an ASCII string with double quotation
+ # - a hex string (two characters per octet of SSID)
+ # - a printf-escaped ASCII string P"<escaped string>"
+ #
ssid="{{ ssid }}"
+
+ # scan_ssid:
+ # 0 = do not scan this SSID with specific Probe Request frames (default)
+ # 1 = scan with SSID-specific Probe Request frames (this can be used to
+ # find APs that do not accept broadcast SSID or use multiple SSIDs;
+ # this will add latency to scanning, so enable this only when needed)
scan_ssid=1
+
{% if security is defined and security.wpa is defined and security.wpa.passphrase is defined %}
- key_mgmt=WPA-PSK
+ # ieee80211w: whether management frame protection is enabled
+ # 0 = disabled (default unless changed with the global pmf parameter)
+ # 1 = optional
+ # 2 = required
+ # The most common configuration options for this based on the PMF (protected
+ # management frames) certification program are:
+ # PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
+ # PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
+ # (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+ # WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE
+ ieee80211w=1
+
+ # key_mgmt: list of accepted authenticated key management protocols
+ # WPA-PSK = WPA pre-shared key (this requires 'psk' field)
+ # WPA-EAP = WPA using EAP authentication
+ # IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
+ # generated WEP keys
+ # NONE = WPA is not used; plaintext or static WEP could be used
+ # WPA-NONE = WPA-None for IBSS (deprecated; use proto=RSN key_mgmt=WPA-PSK
+ # instead)
+ # FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
+ # FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+ # FT-EAP-SHA384 = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+ # and using SHA384
+ # WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
+ # WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+ # SAE = Simultaneous authentication of equals; pre-shared key/password -based
+ # authentication with stronger security than WPA-PSK especially when using
+ # not that strong password; a.k.a. WPA3-Personal
+ # FT-SAE = SAE with FT
+ # WPA-EAP-SUITE-B = Suite B 128-bit level
+ # WPA-EAP-SUITE-B-192 = Suite B 192-bit level
+ # OSEN = Hotspot 2.0 Rel 2 online signup connection
+ # FILS-SHA256 = Fast Initial Link Setup with SHA256
+ # FILS-SHA384 = Fast Initial Link Setup with SHA384
+ # FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
+ # FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+ # OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+ # DPP = Device Provisioning Protocol
+ # If not set, this defaults to: WPA-PSK WPA-EAP
+{% if security.wpa.mode is defined and security.wpa.mode == 'wpa3' %}
+ key_mgmt=SAE
+{% else %}
+ key_mgmt=WPA-PSK WPA-PSK-SHA256
+{% endif %}
+
+ # psk: WPA preshared key; 256-bit pre-shared key
+ # The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
+ # 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
+ # generated using the passphrase and SSID). ASCII passphrase must be between
+ # 8 and 63 characters (inclusive). ext:<name of external PSK field> format can
+ # be used to indicate that the PSK/passphrase is stored in external storage.
+ # This field is not needed, if WPA-EAP is used.
+ # Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
+ # from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
+ # startup and reconfiguration time can be optimized by generating the PSK only
+ # only when the passphrase or SSID has actually changed.
psk="{{ security.wpa.passphrase }}"
{% else %}
key_mgmt=NONE
diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in
index 7d576648a..8dbbc4353 100644
--- a/interface-definitions/interfaces-wireless.xml.in
+++ b/interface-definitions/interfaces-wireless.xml.in
@@ -681,7 +681,7 @@
<properties>
<help>WPA mode</help>
<completionHelp>
- <list>wpa wpa2 wpa+wpa2</list>
+ <list>wpa wpa2 wpa+wpa2 wpa3</list>
</completionHelp>
<valueHelp>
<format>wpa</format>
@@ -696,7 +696,7 @@
<description>Allow both WPA and WPA2</description>
</valueHelp>
<constraint>
- <regex>^(wpa|wpa2|wpa\+wpa2)$</regex>
+ <regex>^(wpa|wpa2|wpa\+wpa2|wpa3)$</regex>
</constraint>
<constraintErrorMessage>Unknown WPA mode</constraintErrorMessage>
</properties>
diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py
index 0e93b6432..a62b44ee5 100755
--- a/smoketest/scripts/cli/test_interfaces_wireless.py
+++ b/smoketest/scripts/cli/test_interfaces_wireless.py
@@ -18,14 +18,16 @@ import os
import re
import unittest
+from vyos.configsession import ConfigSessionError
from base_interfaces_test import BasicInterfaceTest
+
from vyos.util import process_named_running
from vyos.util import check_kmod
from vyos.util import read_file
def get_config_value(interface, key):
tmp = read_file(f'/run/hostapd/{interface}.conf')
- tmp = re.findall(r'\n?{}=+(.*)'.format(key), tmp)
+ tmp = re.findall(f'{key}=+(.*)', tmp)
return tmp[0]
class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
@@ -114,6 +116,8 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
#
# Validate Config
#
+ tmp = get_config_value(interface, 'interface')
+ self.assertEqual(interface, tmp)
# ssid
tmp = get_config_value(interface, 'ssid')
@@ -138,6 +142,63 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
# Check for running process
self.assertTrue(process_named_running('hostapd'))
+ def test_hostapd_wpa_config(self):
+ """ Check if hostapd config is properly generated """
+
+ # Only set the hostapd (access-point) options
+ interface = 'wlan0'
+ phy = 'phy0'
+ ssid = 'ssid'
+ channel = '0'
+ wpa_key = 'VyOSVyOSVyOS'
+ mode = 'n'
+
+ self.session.set(self._base_path + [interface, 'physical-device', phy])
+ self.session.set(self._base_path + [interface, 'type', 'access-point'])
+ self.session.set(self._base_path + [interface, 'mode', 'mode'])
+
+ # SSID must be set
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.set(self._base_path + [interface, 'ssid', ssid])
+
+ # Channel must be set
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.set(self._base_path + [interface, 'channel', channel])
+
+
+ self.session.set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa2'])
+ self.session.set(self._base_path + [interface, 'security', 'wpa', 'passphrase', wpa_key])
+
+ self.session.commit()
+
+ #
+ # Validate Config
+ #
+ tmp = get_config_value(interface, 'interface')
+ self.assertEqual(interface, tmp)
+
+ tmp = get_config_value(interface, 'hw_mode')
+ self.assertEqual(mode, tmp)
+
+ # WPA key
+ tmp = get_config_value(interface, 'wpa')
+ self.assertEqual('2', tmp)
+ tmp = get_config_value(interface, 'wpa_passphrase')
+ self.assertEqual(wpa_key, tmp)
+
+ # SSID
+ tmp = get_config_value(interface, 'ssid')
+ self.assertEqual(ssid, tmp)
+
+ # channel
+ tmp = get_config_value(interface, 'channel')
+ self.assertEqual(channel, tmp)
+
+ # Check for running process
+ self.assertTrue(process_named_running('hostapd'))
+
if __name__ == '__main__':
check_kmod('mac80211_hwsim')
unittest.main()