Repository: openwisp/netjsonconfig

Issue:
[feature] Support more WPA EAP client parameters
**Is your feature request related to a problem? Please describe.**
While setting up a WPA Eap client I noticed some config parameters that are available in the OpenWrt UI are not present in our schema.
Let's fix that.

**Describe the solution you'd like**
Here's screenshot of the OpenWrt UI for WPA EAP client options

![Screenshot from 2024-08-29 15-05-40](https://github.com/user-attachments/assets/9cd27b2b-ba04-47f9-9132-2933a3e69766)

Discussion:

Solution patch:
diff --git a/docs/source/backends/openwrt.rst b/docs/source/backends/openwrt.rst
index f774f24..25da470 100644
--- a/docs/source/backends/openwrt.rst
+++ b/docs/source/backends/openwrt.rst
@@ -1427,8 +1427,13 @@ WPA2 Enterprise (802.1x) client
                         "protocol": "wpa2_enterprise",
                         "cipher": "auto",
                         "eap_type": "tls",
+                        "anonymous_identity": "anonymous",
                         "identity": "test-identity",
                         "password": "test-password",
+                        "ca_cert_usesystem": True,
+                        "subject_match": "CN = wifi.openwisp.io",
+                        "altsubject_match": ["DNS Name: wifi.openwisp.io"],
+                        "domain_match": ["wifi.openwisp.io"],
                     },
                 },
             }
@@ -1442,8 +1447,12 @@ UCI Output:
     package wireless
 
     config wifi-iface 'wifi_wlan0'
+            list altsubject_match 'DNS Name: wifi.openwisp.io'
+            option anonymous_identity 'anonymous'
             option bssid '00:26:b9:20:5f:09'
+            option ca_cert_usesystem '1'
             option device 'radio0'
+            list domain_match 'wifi.openwisp.io'
             option eap_type 'tls'
             option encryption 'wpa2'
             option identity 'test-identity'
@@ -1451,6 +1460,7 @@ UCI Output:
             option mode 'sta'
             option password 'test-password'
             option ssid 'enterprise-client'
+            option subject_match 'CN = wifi.openwisp.io'
 
 WPA3 Personal (Simultaneous Authentication of Equals)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/netjsonconfig/backends/openwrt/converters/wireless.py b/netjsonconfig/backends/openwrt/converters/wireless.py
index 6609861..d1cd2e1 100644
--- a/netjsonconfig/backends/openwrt/converters/wireless.py
+++ b/netjsonconfig/backends/openwrt/converters/wireless.py
@@ -283,10 +283,16 @@ class Wireless(OpenWrtConverter):
         'vlan_bridge',
         'eap_type',
         'auth',
+        'anonymous_identity',
         'identity',
         'password',
         'ca_cert',
         'client_cert',
+        'ca_cert_usesystem',
+        'subject_match',
+        'altsubject_match',
+        'domain_match',
+        'domain_suffix_match',
         'priv_key',
         'priv_key_pwd',
         'wps_config',
diff --git a/netjsonconfig/backends/openwrt/schema.py b/netjsonconfig/backends/openwrt/schema.py
index 2198429..5833576 100644
--- a/netjsonconfig/backends/openwrt/schema.py
+++ b/netjsonconfig/backends/openwrt/schema.py
@@ -900,6 +900,62 @@ schema = merge_config(
                     },
                 }
             },
+            "encryption_wpa_enterprise_sta_base_settings": {
+                "properties": {
+                    "ca_cert_usesystem": {
+                        "title": "Use system certificates",
+                        "type": "boolean",
+                        "default": False,
+                        "format": "checkbox",
+                        "description": (
+                            'Validate server certificate using built-in'
+                            ' system CA bundle, requires the "ca-bundle" package'
+                        ),
+                        "propertyOrder": 7.9,
+                    },
+                    "subject_match": {
+                        "title": "Certificate constraint (Subject)",
+                        "type": "string",
+                        "description": (
+                            "Certificate constraint substring"
+                            " - e.g. /CN=wifi.mycompany.com See `logread -f` during"
+                            " handshake for actual values"
+                        ),
+                        "propertyOrder": 8.9,
+                    },
+                    "altsubject_match": {
+                        "title": "Certificate constraint (SAN)",
+                        "description": (
+                            "Certificate constraint(s) via Subject Alternate"
+                            " Name values (supported attributes: EMAIL, DNS, URI)"
+                            " - e.g. DNS:wifi.mycompany.com"
+                        ),
+                        "type": "array",
+                        "items": {"type": "string"},
+                        "propertyOrder": 8.91,
+                    },
+                    "domain_match": {
+                        "title": "Certificate constraint (Domain)",
+                        "description": (
+                            "Certificate constraint(s) against DNS SAN values"
+                            " (if available) or Subject CN (exact match)"
+                        ),
+                        "type": "array",
+                        "items": {"type": "string"},
+                        "propertyOrder": 8.92,
+                    },
+                    "domain_suffix_match": {
+                        "title": "Certificate constraint (Wildcard)",
+                        "description": (
+                            "Certificate constraint(s) against DNS SAN values "
+                            "(if available) or Subject CN (suffix match)"
+                        ),
+                        "type": "array",
+                        "items": {"type": "string"},
+                        "propertyOrder": 8.93,
+                    },
+                }
+            },
         },
         "properties": {
             "general": {
diff --git a/netjsonconfig/schema.py b/netjsonconfig/schema.py
index bd72f08..d169e16 100644
--- a/netjsonconfig/schema.py
+++ b/netjsonconfig/schema.py
@@ -662,6 +662,7 @@ schema = {
                     "propertyOrder": 5,
                 },
                 "identity": {"type": "string", "propertyOrder": 6},
+                "anonymous_identity": {"type": "string", "propertyOrder": 6.1},
                 "password": {"type": "string", "propertyOrder": 7},
                 "ca_cert": {
                     "type": "string",


Test patch:
diff --git a/tests/openwrt/test_encryption.py b/tests/openwrt/test_encryption.py
index 6782edb..e40ff71 100644
--- a/tests/openwrt/test_encryption.py
+++ b/tests/openwrt/test_encryption.py
@@ -563,8 +563,12 @@ config wifi-iface 'wifi_wlan0'
                         "cipher": "auto",
                         "eap_type": "ttls",
                         "auth": "MSCHAPV2",
+                        "anonymous_identity": "anonymous",
                         "identity": "test-identity",
                         "password": "test-password",
+                        "client_cert": "/etc/ssl/wifi.openwisp.io/cert.crt",
+                        "priv_key": "/etc/ssl/wifi.openwisp.io/private.key",
+                        "domain_match": ["wifi.openwisp.io"],
                     },
                 },
             }
@@ -573,15 +577,19 @@ config wifi-iface 'wifi_wlan0'
     _wpa2_enterprise_ttls_client_uci = """package wireless
 
 config wifi-iface 'wifi_wlan0'
+    option anonymous_identity 'anonymous'
     option auth 'MSCHAPV2'
     option bssid '00:26:b9:20:5f:09'
+    option client_cert '/etc/ssl/wifi.openwisp.io/cert.crt'
     option device 'radio0'
+    list domain_match 'wifi.openwisp.io'
     option eap_type 'ttls'
     option encryption 'wpa2'
     option identity 'test-identity'
     option ifname 'wlan0'
     option mode 'sta'
     option password 'test-password'
+    option priv_key '/etc/ssl/wifi.openwisp.io/private.key'
     option ssid 'enterprise-client'
 """