From 22b07ff73e0b3429b36f75694a082a68a4fdb013 Mon Sep 17 00:00:00 2001 From: David Lam Date: Tue, 14 Jan 2020 00:27:28 -0800 Subject: [PATCH] hostapd: add support for subject validation The wpa_supplicant supports certificate subject validation via the subject match(2) and altsubject_match(2) fields. domain_match(2) and domain_suffix_match(2) fields are also supported for advanced matches. This validation is especially important when connecting to access points that use PAP as the Phase 2 authentication type. Without proper validation, the user's password can be transmitted to a rogue access point in plaintext without the user's knowledge. Most organizations already require these attributes to be included to ensure that the connection from the STA and the AP is secure. Includes LuCI changes via openwrt/luci#3444. From the documentation: subject_match - Constraint for server certificate subject. This substring is matched against the subject of the authentication server certificate. If this string is set, the server sertificate is only accepted if it contains this string in the subject. The subject string is in following format: /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as .example.com subject_match2 - Constraint for server certificate subject. This field is like subject_match, but used for phase 2 (inside EAP-TTLS/PEAP/FAST tunnel) authentication. altsubject_match - Constraint for server certificate alt. subject. Semicolon separated string of entries to be matched against the alternative subject name of the authentication server certificate. If this string is set, the server sertificate is only accepted if it contains one of the entries in an alternative subject name extension. altSubjectName string is in following format: TYPE:VALUE Example: EMAIL:server@example.com Example: DNS:server.example.com;DNS:server2.example.com Following types are supported: EMAIL, DNS, URI altsubject_match2 - Constraint for server certificate alt. subject. This field is like altsubject_match, but used for phase 2 (inside EAP-TTLS/PEAP/FAST tunnel) authentication. domain_match - Constraint for server domain name. If set, this FQDN is used as a full match requirement for the server certificate in SubjectAltName dNSName element(s). If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same full match comparison. This behavior is similar to domain_suffix_match, but has the requirement of a full match, i.e., no subdomains or wildcard matches are allowed. Case-insensitive comparison is used, so "Example.com" matches "example.com", but would not match "test.Example.com". More than one match string can be provided by using semicolons to separate the strings (e.g., example.org;example.com). When multiple strings are specified, a match with any one of the values is considered a sufficient match for the certificate, i.e., the conditions are ORed together. domain_match2 - Constraint for server domain name. This field is like domain_match, but used for phase 2 (inside EAP-TTLS/PEAP/FAST tunnel) authentication. domain_suffix_match - Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for the AAA server certificate in SubjectAltName dNSName element(s). If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Suffix match here means that the host/domain name is compared one label at a time starting from the top-level domain and all the labels in domain_suffix_match shall be included in the certificate. The certificate may include additional sub-level labels in addition to the required labels. More than one match string can be provided by using semicolons to separate the strings (e.g., example.org;example.com). When multiple strings are specified, a match with any one of the values is considered a sufficient match for the certificate, i.e., the conditions are ORed together. For example, domain_suffix_match=example.com would match test.example.com but would not match test-example.com. This field is like domain_match, but used for phase 2 (inside EAP-TTLS/PEAP/FAST tunnel) authentication. domain_suffix_match2 - Constraint for server domain name. This field is like domain_suffix_match, but used for phase 2 (inside EAP-TTLS/PEAP/FAST tunnel) authentication. Signed-off-by: David Lam --- package/network/services/hostapd/Makefile | 2 +- .../network/services/hostapd/files/hostapd.sh | 92 +++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile index 11d0d7a9ce..8dfcd89cc4 100644 --- a/package/network/services/hostapd/Makefile +++ b/package/network/services/hostapd/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hostapd -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE_URL:=http://w1.fi/hostap.git PKG_SOURCE_PROTO:=git diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 3d4e57db25..dcbabaf8f1 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -202,6 +202,9 @@ hostapd_common_add_bss_config() { config_add_string radius_client_addr config_add_string iapp_interface config_add_string eap_type ca_cert client_cert identity anonymous_identity auth priv_key priv_key_pwd + config_add_string subject_match subject_match2 + config_add_array altsubject_match altsubject_match2 + config_add_array domain_match domain_match2 domain_suffix_match domain_suffix_match2 config_add_string ieee80211w_mgmt_cipher config_add_int dynamic_vlan vlan_naming @@ -872,6 +875,36 @@ wpa_supplicant_add_network() { append network_data "client_cert=\"$client_cert\"" "$N$T" append network_data "private_key=\"$priv_key\"" "$N$T" append network_data "private_key_passwd=\"$priv_key_pwd\"" "$N$T" + + json_get_vars subject_match + [ -n "$subject_match" ] && append network_data "subject_match=\"$subject_match\"" "$N$T" + + json_get_values altsubject_match altsubject_match + if [ -n "$altsubject_match" ]; then + local list= + for x in $altsubject_match; do + append list "$x" ";" + done + append network_data "altsubject_match=\"$list\"" "$N$T" + fi + + json_get_values domain_match domain_match + if [ -n "$domain_match" ]; then + local list= + for x in $domain_match; do + append list "$x" ";" + done + append network_data "domain_match=\"$list\"" "$N$T" + fi + + json_get_values domain_suffix_match domain_suffix_match + if [ -n "$domain_suffix_match" ]; then + local list= + for x in $domain_suffix_match; do + append list "$x" ";" + done + append network_data "domain_suffix_match=\"$list\"" "$N$T" + fi ;; fast|peap|ttls) json_get_vars auth password ca_cert2 client_cert2 priv_key2 priv_key2_pwd @@ -887,6 +920,36 @@ wpa_supplicant_add_network() { append network_data "password=\"$password\"" "$N$T" fi + json_get_vars subject_match + [ -n "$subject_match" ] && append network_data "subject_match=\"$subject_match\"" "$N$T" + + json_get_values altsubject_match altsubject_match + if [ -n "$altsubject_match" ]; then + local list= + for x in $altsubject_match; do + append list "$x" ";" + done + append network_data "altsubject_match=\"$list\"" "$N$T" + fi + + json_get_values domain_match domain_match + if [ -n "$domain_match" ]; then + local list= + for x in $domain_match; do + append list "$x" ";" + done + append network_data "domain_match=\"$list\"" "$N$T" + fi + + json_get_values domain_suffix_match domain_suffix_match + if [ -n "$domain_suffix_match" ]; then + local list= + for x in $domain_suffix_match; do + append list "$x" ";" + done + append network_data "domain_suffix_match=\"$list\"" "$N$T" + fi + phase2proto="auth=" case "$auth" in "auth"*) @@ -896,6 +959,35 @@ wpa_supplicant_add_network() { auth="$(echo $auth | cut -b 5- )" [ "$eap_type" = "ttls" ] && phase2proto="autheap=" + json_get_vars subject_match2 + [ -n "$subject_match2" ] && append network_data "subject_match2=\"$subject_match2\"" "$N$T" + + json_get_values altsubject_match2 altsubject_match2 + if [ -n "$altsubject_match2" ]; then + local list= + for x in $altsubject_match2; do + append list "$x" ";" + done + append network_data "altsubject_match2=\"$list\"" "$N$T" + fi + + json_get_values domain_match2 domain_match2 + if [ -n "$domain_match2" ]; then + local list= + for x in $domain_match2; do + append list "$x" ";" + done + append network_data "domain_match2=\"$list\"" "$N$T" + fi + + json_get_values domain_suffix_match2 domain_suffix_match2 + if [ -n "$domain_suffix_match2" ]; then + local list= + for x in $domain_suffix_match2; do + append list "$x" ";" + done + append network_data "domain_suffix_match2=\"$list\"" "$N$T" + fi ;; esac append network_data "phase2=\"$phase2proto$auth\"" "$N$T"