From 6ca0853d1847cea018e892f5423998cdf8cde763 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 22 Nov 2012 00:48:48 +0200 Subject: [PATCH] HS 2.0R2 AP: Use Subscr Remediation request from RADIUS server If the RADIUS server includes the WFA RADIUS VSA in Access-Accept to indicate need for subscription remediation, copy the server URL from the message and send it to the station after successfully completed 4-way handshake (i.e., after PTK is set to allow PMF to work) in a WNM-Notification. AP must not allow PMKSA caching to be used after subscription remediation association, so do not add the PMKSA cache entry whenever the authentication server is indicating need for subscription remediation. This allows station reassociation to use EAP authentication to move to non-remediation connection. Signed-hostap: Jouni Malinen --- src/ap/ieee802_1x.c | 90 ++++++++++++++++++++++++++++++++++++++++++++- src/ap/sta_info.c | 1 + src/ap/sta_info.h | 3 ++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 9c2488cdd..97ba601b3 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -30,6 +30,7 @@ #include "ap_config.h" #include "ap_drv_ops.h" #include "wps_hostapd.h" +#include "hs20.h" #include "ieee802_1x.h" @@ -1238,6 +1239,74 @@ static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, } +#ifdef CONFIG_HS20 + +static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) +{ + sta->remediation = 1; + os_free(sta->remediation_url); + if (len > 2) { + sta->remediation_url = os_malloc(len); + if (!sta->remediation_url) + return; + sta->remediation_method = pos[0]; + os_memcpy(sta->remediation_url, pos + 1, len - 1); + sta->remediation_url[len - 1] = '\0'; + wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " + "for " MACSTR " - server method %u URL %s", + MAC2STR(sta->addr), sta->remediation_method, + sta->remediation_url); + } else { + sta->remediation_url = NULL; + wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " + "for " MACSTR, MAC2STR(sta->addr)); + } + /* TODO: assign the STA into remediation VLAN or add filtering */ +} + +#endif /* CONFIG_HS20 */ + + +static void ieee802_1x_check_hs20(struct hostapd_data *hapd, + struct sta_info *sta, + struct radius_msg *msg) +{ +#ifdef CONFIG_HS20 + u8 *buf, *pos, *end, type, sublen; + size_t len; + + buf = NULL; + sta->remediation = 0; + for (;;) { + if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, + &buf, &len, buf) < 0) + break; + if (len < 6) + continue; + pos = buf; + end = buf + len; + if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) + continue; + pos += 4; + + type = *pos++; + sublen = *pos++; + if (sublen < 2) + continue; /* invalid length */ + sublen -= 2; /* skip header */ + if (pos + sublen > end) + continue; /* invalid WFA VSA */ + + switch (type) { + case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION: + ieee802_1x_hs20_sub_rem(sta, pos, sublen); + break; + } + } +#endif /* CONFIG_HS20 */ +} + + struct sta_id_search { u8 identifier; struct eapol_state_machine *sm; @@ -1396,7 +1465,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, ieee802_1x_store_radius_class(hapd, sta, msg); ieee802_1x_update_sta_identity(hapd, sta, msg); ieee802_1x_update_sta_cui(hapd, sta, msg); - if (sm->eap_if->eapKeyAvailable && + ieee802_1x_check_hs20(hapd, sta, msg); + if (sm->eap_if->eapKeyAvailable && !sta->remediation && wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, session_timeout_set ? (int) session_timeout : -1, sm) == 0) { @@ -2150,8 +2220,24 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, /* TODO: get PMKLifetime from WPA parameters */ static const int dot11RSNAConfigPMKLifetime = 43200; +#ifdef CONFIG_HS20 + if (success) { + if (sta->remediation) { + wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification " + "to " MACSTR " to indicate Subscription " + "Remediation", + MAC2STR(sta->addr)); + hs20_send_wnm_notification(hapd, sta->addr, + sta->remediation_method, + sta->remediation_url); + os_free(sta->remediation_url); + sta->remediation_url = NULL; + } + } +#endif /* CONFIG_HS20 */ + key = ieee802_1x_get_key(sta->eapol_sm, &len); - if (success && key && len >= PMK_LEN && + if (success && key && len >= PMK_LEN && !sta->remediation && wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, sta->eapol_sm) == 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 24e764d66..811a42a17 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -265,6 +265,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) hostapd_free_psk_list(sta->psk); os_free(sta->identity); os_free(sta->radius_cui); + os_free(sta->remediation_url); #ifdef CONFIG_SAE sae_clear_data(sta->sae); diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 240b92634..a784439cf 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -57,6 +57,7 @@ struct sta_info { unsigned int ht_20mhz_set:1; unsigned int no_p2p_set:1; unsigned int qos_map_enabled:1; + unsigned int remediation:1; u16 auth_alg; u8 previous_ap[6]; @@ -125,6 +126,8 @@ struct sta_info { struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */ struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */ + u8 remediation_method; + char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */ struct os_reltime connected_time;