From b0e91e3877b2429c21229fc27fc29dec5115eb97 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 17 Feb 2019 17:22:37 +0200 Subject: [PATCH] SAE: VLAN assignment based on SAE Password Identifier The new sae_password parameter [|vlanid=] can now be used to assign stations to a specific VLAN based on which SAE Password Identifier they use. This is similar to the WPA2-Enterprise case where the RADIUS server can assign stations to different VLANs and the WPA2-Personal case where vlanid parameter in wpa_psk_file is used. Signed-off-by: Jouni Malinen --- hostapd/config_file.c | 8 ++++++++ hostapd/hostapd.conf | 26 +++++++++++++++++--------- src/ap/ap_config.h | 1 + src/ap/ieee802_11.c | 38 ++++++++++++++++++++++++++++++++++++++ src/common/sae.h | 1 + 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index c8ff7a06a..c22731e32 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2333,6 +2333,14 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val) pos = pos2 + ETH_ALEN * 3 - 1; } + pos2 = os_strstr(pos, "|vlanid="); + if (pos2) { + if (!end) + end = pos2; + pos2 += 8; + pw->vlan_id = atoi(pos2); + } + pos2 = os_strstr(pos, "|id="); if (pos2) { if (!end) diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index ee8f9610c..c7e23ffe1 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1188,7 +1188,7 @@ own_ip_addr=127.0.0.1 # VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can # be used to set static client MAC address to VLAN ID mapping. # Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2 -# passphrase from wpa_psk_file. +# passphrase from wpa_psk_file or vlan_id parameter from sae_password. # 0 = disabled (default); only VLAN IDs from accept_mac_file will be used # 1 = optional; use default interface if RADIUS server does not include VLAN ID # 2 = required; reject authentication if RADIUS server does not include VLAN ID @@ -1538,21 +1538,29 @@ own_ip_addr=127.0.0.1 # corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value # starts with the password (dot11RSNAConfigPasswordCredential). That value can # be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and -# by optional password identifier (dot11RSNAConfigPasswordIdentifier). If the -# peer MAC address is not included or is set to the wildcard address +# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In +# addition, an optional VLAN ID specification can be used to bind the station +# to the specified VLAN whenver the specific SAE password entry is used. +# +# If the peer MAC address is not included or is set to the wildcard address # (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a # specific peer MAC address is included, only a station with that MAC address -# is allowed to use the entry. If the password identifier (with non-zero length) -# is included, the entry is limited to be used only with that specified -# identifier. The last matching (based on peer MAC address and identifier) entry -# is used to select which password to use. Setting sae_password to an empty -# string has a special meaning of removing all previously added entries. +# is allowed to use the entry. +# +# If the password identifier (with non-zero length) is included, the entry is +# limited to be used only with that specified identifier. + +# The last matching (based on peer MAC address and identifier) entry is used to +# select which password to use. Setting sae_password to an empty string has a +# special meaning of removing all previously added entries. +# # sae_password uses the following encoding: -#[|mac=][|id=] +#[|mac=][|vlanid=][|id=] # Examples: #sae_password=secret #sae_password=really secret|mac=ff:ff:ff:ff:ff:ff #sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier +#sae_password=example secret|vlanid=3|id=pw identifier # SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold) # This parameter defines how many open SAE instances can be in progress at the diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index ac07b577c..897af5019 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -249,6 +249,7 @@ struct sae_password_entry { char *password; char *identifier; u8 peer_addr[ETH_ALEN]; + int vlan_id; }; /** diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index c6138e1af..bc45cd71f 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -420,6 +420,15 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, return NULL; } + if (pw && pw->vlan_id) { + if (!sta->sae->tmp) { + wpa_printf(MSG_INFO, + "SAE: No temporary data allocated - cannot store VLAN ID"); + return NULL; + } + sta->sae->tmp->vlan_id = pw->vlan_id; + } + buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN + (rx_id ? 3 + os_strlen(rx_id) : 0)); if (buf == NULL) @@ -629,6 +638,35 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd, void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta) { +#ifndef CONFIG_NO_VLAN + struct vlan_description vlan_desc; + + if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) { + wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR + " to VLAN ID %d", + MAC2STR(sta->addr), sta->sae->tmp->vlan_id); + + os_memset(&vlan_desc, 0, sizeof(vlan_desc)); + vlan_desc.notempty = 1; + vlan_desc.untagged = sta->sae->tmp->vlan_id; + if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { + wpa_printf(MSG_INFO, + "Invalid VLAN ID %d in sae_password", + sta->sae->tmp->vlan_id); + return; + } + + if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 || + ap_sta_bind_vlan(hapd, sta) < 0) { + wpa_printf(MSG_INFO, + "Failed to assign VLAN ID %d from sae_password to " + MACSTR, sta->sae->tmp->vlan_id, + MAC2STR(sta->addr)); + return; + } + } +#endif /* CONFIG_NO_VLAN */ + sta->flags |= WLAN_STA_AUTH; sta->auth_alg = WLAN_AUTH_SAE; mlme_authenticate_indication(hapd, sta); diff --git a/src/common/sae.h b/src/common/sae.h index 3fbcb58d1..bb33761f9 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -40,6 +40,7 @@ struct sae_temporary_data { struct crypto_bignum *order_buf; struct wpabuf *anti_clogging_token; char *pw_id; + int vlan_id; }; enum sae_state {