From 955567bc0948135be62871800b556922c661bf57 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 2 Aug 2012 18:48:31 +0300 Subject: [PATCH 1/1] Interworking: Add support for using Roaming Consortium OI for matching Each cred block can now be matched based on Roaming Consortium OI as an alternative mechanism to using NAI Realm information. This may be optimized for efficiency in the future since Roaming Consortium information is available in scan results without having to go through ANQP queries. In addition, this is easier to support in case there is a large number of realms that can be used for authentication. Signed-hostap: Jouni Malinen --- wpa_supplicant/config.c | 14 +++ wpa_supplicant/config.h | 18 ++++ wpa_supplicant/interworking.c | 167 +++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant.conf | 20 ++++ 4 files changed, 219 insertions(+) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 9b252e9a1..54a767e10 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2350,6 +2350,20 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "roaming_consortium") == 0) { + if (len < 3 || len > sizeof(cred->roaming_consortium)) { + wpa_printf(MSG_ERROR, "Line %d: invalid " + "roaming_consortium length %d (3..15 " + "expected)", line, (int) len); + os_free(val); + return -1; + } + os_memcpy(cred->roaming_consortium, val, len); + cred->roaming_consortium_len = len; + os_free(val); + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 5db919408..6f4f80182 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -149,6 +149,24 @@ struct wpa_cred { */ char *domain; + /** + * roaming_consortium - Roaming Consortium OI + * + * If roaming_consortium_len is non-zero, this field contains the + * Roaming Consortium OI that can be used to determine which access + * points support authentication with this credential. This is an + * alternative to the use of the realm parameter. When using Roaming + * Consortium to match the network, the EAP parameters need to be + * pre-configured with the credential since the NAI Realm information + * may not be available or fetched. + */ + u8 roaming_consortium[15]; + + /** + * roaming_consortium_len - Length of roaming_consortium + */ + size_t roaming_consortium_len; + /** * eap_method - EAP method to use * diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 86f2ee3e9..04a508db0 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -731,6 +731,114 @@ fail: } +static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, + size_t rc_len) +{ + const u8 *pos, *end; + u8 lens; + + if (ie == NULL) + return 0; + + pos = ie + 2; + end = ie + 2 + ie[1]; + + /* Roaming Consortium element: + * Number of ANQP OIs + * OI #1 and #2 lengths + * OI #1, [OI #2], [OI #3] + */ + + if (pos + 2 > end) + return 0; + + pos++; /* skip Number of ANQP OIs */ + lens = *pos++; + if (pos + (lens & 0x0f) + (lens >> 4) > end) + return 0; + + if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + pos += lens & 0x0f; + + if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + pos += lens >> 4; + + if (pos < end && (size_t) (end - pos) == rc_len && + os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + + return 0; +} + + +static int roaming_consortium_anqp_match(const struct wpabuf *anqp, + const u8 *rc_id, size_t rc_len) +{ + const u8 *pos, *end; + u8 len; + + if (anqp == NULL) + return 0; + + pos = wpabuf_head(anqp); + end = pos + wpabuf_len(anqp); + + /* Set of duples */ + while (pos < end) { + len = *pos++; + if (pos + len > end) + break; + if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + pos += len; + } + + return 0; +} + + +static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, + const u8 *rc_id, size_t rc_len) +{ + return roaming_consortium_element_match(ie, rc_id, rc_len) || + roaming_consortium_anqp_match(anqp, rc_id, rc_len); +} + + +static struct wpa_cred * interworking_credentials_available_roaming_consortium( + struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + struct wpa_cred *cred, *selected = NULL; + const u8 *ie; + + ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); + + if (ie == NULL && bss->anqp_roaming_consortium == NULL) + return NULL; + + if (wpa_s->conf->cred == NULL) + return NULL; + + for (cred = wpa_s->conf->cred; cred; cred = cred->next) { + if (cred->roaming_consortium_len == 0) + continue; + + if (!roaming_consortium_match(ie, bss->anqp_roaming_consortium, + cred->roaming_consortium, + cred->roaming_consortium_len)) + continue; + + if (selected == NULL || + selected->priority < cred->priority) + selected = cred; + } + + return selected; +} + + static int interworking_set_eap_params(struct wpa_ssid *ssid, struct wpa_cred *cred, int ttls) { @@ -817,6 +925,52 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, } +static int interworking_connect_roaming_consortium( + struct wpa_supplicant *wpa_s, struct wpa_cred *cred, + struct wpa_bss *bss, const u8 *ssid_ie) +{ + struct wpa_ssid *ssid; + + wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on " + "roaming consortium match", MAC2STR(bss->bssid)); + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) + return -1; + wpas_notify_network_added(wpa_s, ssid); + wpa_config_set_network_defaults(ssid); + ssid->priority = cred->priority; + ssid->temporary = 1; + ssid->ssid = os_zalloc(ssid_ie[1] + 1); + if (ssid->ssid == NULL) + goto fail; + os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]); + ssid->ssid_len = ssid_ie[1]; + + if (cred->eap_method == NULL) { + wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for " + "credential using roaming consortium"); + goto fail; + } + + if (interworking_set_eap_params( + ssid, cred, + cred->eap_method->vendor == EAP_VENDOR_IETF && + cred->eap_method->method == EAP_TYPE_TTLS) < 0) + goto fail; + + wpa_config_update_prio_list(wpa_s->conf); + interworking_reconnect(wpa_s); + + return 0; + +fail: + wpas_notify_network_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + return -1; +} + + int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_cred *cred; @@ -836,6 +990,12 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) return -1; } + cred = interworking_credentials_available_roaming_consortium(wpa_s, + bss); + if (cred) + return interworking_connect_roaming_consortium(wpa_s, cred, + bss, ie); + realm = nai_realm_parse(bss->anqp_nai_realm, &count); if (realm == NULL) { wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " @@ -1062,6 +1222,13 @@ static struct wpa_cred * interworking_credentials_available( if (!cred) cred = cred2; + cred2 = interworking_credentials_available_roaming_consortium(wpa_s, + bss); + if (cred && cred2 && cred2->priority >= cred->priority) + cred = cred2; + if (!cred) + cred = cred2; + return cred; } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index fa4e39773..af0da2065 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -336,6 +336,15 @@ fast_reauth=1 # This is used to compare against the Domain Name List to figure out # whether the AP is operated by the Home SP. # +# roaming_consortium: Roaming Consortium OI +# If roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that can be used to determine which access +# points support authentication with this credential. This is an +# alternative to the use of the realm parameter. When using Roaming +# Consortium to match the network, the EAP parameters need to be +# pre-configured with the credential since the NAI Realm information +# may not be available or fetched. +# # eap: Pre-configured EAP method # This optional field can be used to specify which EAP method will be # used with this credential. If not set, the EAP method is selected @@ -361,6 +370,17 @@ fast_reauth=1 # imsi="310026-000000000" # milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82" #} +# +#cred={ +# realm="example.com" +# username="user" +# password="password" +# ca_cert="/etc/wpa_supplicant/ca.pem" +# domain="example.com" +# roaming_consortium=223344 +# eap=TTLS +# phase2="auth=MSCHAPV2" +#} # Hotspot 2.0 # hs20=1 -- 2.39.2