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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2012-08-02 18:48:31 +03:00
parent 8ca93c59e0
commit 955567bc09
4 changed files with 219 additions and 0 deletions

View File

@ -2350,6 +2350,20 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0; 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) { if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var); line, var);

View File

@ -149,6 +149,24 @@ struct wpa_cred {
*/ */
char *domain; 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 * eap_method - EAP method to use
* *

View File

@ -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 <OI Length, OI> 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, static int interworking_set_eap_params(struct wpa_ssid *ssid,
struct wpa_cred *cred, int ttls) 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) int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{ {
struct wpa_cred *cred; struct wpa_cred *cred;
@ -836,6 +990,12 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
return -1; 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); realm = nai_realm_parse(bss->anqp_nai_realm, &count);
if (realm == NULL) { if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
@ -1062,6 +1222,13 @@ static struct wpa_cred * interworking_credentials_available(
if (!cred) if (!cred)
cred = cred2; 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; return cred;
} }

View File

@ -336,6 +336,15 @@ fast_reauth=1
# This is used to compare against the Domain Name List to figure out # This is used to compare against the Domain Name List to figure out
# whether the AP is operated by the Home SP. # 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 # eap: Pre-configured EAP method
# This optional field can be used to specify which EAP method will be # 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 # used with this credential. If not set, the EAP method is selected
@ -361,6 +370,17 @@ fast_reauth=1
# imsi="310026-000000000" # imsi="310026-000000000"
# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82" # 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 # Hotspot 2.0
# hs20=1 # hs20=1