]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Interworking: Add support for using Roaming Consortium OI for matching
authorJouni Malinen <j@w1.fi>
Thu, 2 Aug 2012 15:48:31 +0000 (18:48 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 2 Aug 2012 15:48:31 +0000 (18:48 +0300)
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>

wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/interworking.c
wpa_supplicant/wpa_supplicant.conf

index 9b252e9a11dc6261628c99a74ebb9d4e7b2899bc..54a767e10da00e59c294e267e0bee284d59f659d 100644 (file)
@@ -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);
index 5db9194086d7d8f77d28efa6ad63f80d27d7738c..6f4f8018297a7f4ebef65fafe3c6dec3adf0b5f5 100644 (file)
@@ -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
         *
index 86f2ee3e96aae0c20ddcb5a1018b7a9226f08e69..04a508db0bd509ed7cfbe57e6a47c7069018db22 100644 (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,
                                       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;
 }
 
index fa4e39773631a80407e60515a514b3ea99532b92..af0da2065a20670a944dee20ae176b08ecc085b4 100644 (file)
@@ -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