Until now hotspot 2.0 credentials were only supporting one home OI (with roaming_consortium option) and one required home OI (with required_roaming_consortium option). To improve the compliance with Passpoint specification, this changeset adds the support for multiple home and required OIs. The lists of OIs are provided using two new configuration options home_ois and required_home_ois that expect a list of OI formatted as the roaming_consortiums list. It allows to keep the old options to avoid breaking currently running configurations and better fits the vocabulary used in the spec. The OI match algorithm is updated to implement the behavior described in Passpoint spec. 3.2 paragraph 9.1.2 (Home OIs nodes description PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>). Signed-off-by: Damien Dejean <damiendejean@xxxxxxxxxxxx> --- hs20/client/osu_client.c | 8 +- tests/hwsim/test_ap_hs20.py | 62 +++++------ tests/hwsim/test_dbus.py | 4 +- tests/hwsim/test_wpas_config.py | 4 +- tests/hwsim/test_wpas_ctrl.py | 8 +- tests/hwsim/wpasupplicant.py | 10 +- wpa_supplicant/config.c | 169 +++++++++++++++++++++++------ wpa_supplicant/config.h | 50 ++++++--- wpa_supplicant/config_file.c | 38 +++++-- wpa_supplicant/interworking.c | 90 ++++++++------- wpa_supplicant/wpa_supplicant.conf | 20 ++++ 11 files changed, 315 insertions(+), 148 deletions(-) diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c index 01e7b7553..cc5e884bf 100644 --- a/hs20/client/osu_client.c +++ b/hs20/client/osu_client.c @@ -1231,12 +1231,12 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id, homeoi, required); if (required) { - if (set_cred(ctx->ifname, id, "required_roaming_consortium", + if (set_cred(ctx->ifname, id, "required_home_ois", homeoi) < 0) - wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium"); + wpa_printf(MSG_INFO, "Failed to set cred required_home_ois"); } else { - if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0) - wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium"); + if (set_cred(ctx->ifname, id, "home_ois", homeoi) < 0) + wpa_printf(MSG_INFO, "Failed to set cred home_ois"); } xml_node_get_text_free(ctx->xml, homeoi); diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py index c981b3547..f90745021 100644 --- a/tests/hwsim/test_ap_hs20.py +++ b/tests/hwsim/test_ap_hs20.py @@ -1092,7 +1092,7 @@ def test_ap_hs20_roaming_consortium(dev, apdev): 'password': "password", 'domain': "example.com", 'ca_cert': "auth_serv/ca.pem", - 'roaming_consortium': consortium, + 'home_ois': [consortium], 'eap': "PEAP"}) interworking_select(dev[0], bssid, "home", freq="2412") interworking_connect(dev[0], bssid, "PEAP") @@ -1161,7 +1161,7 @@ def test_ap_hs20_roaming_consortium_invalid(dev, apdev): 'password': "password", 'domain': "example.com", 'ca_cert': "auth_serv/ca.pem", - 'roaming_consortium': "fedcba", + 'home_ois': ["fedcba"], 'eap': "PEAP"}) interworking_select(dev[0], bssid, "home", freq="2412", no_match=True) @@ -1180,7 +1180,7 @@ def test_ap_hs20_roaming_consortium_element(dev, apdev): 'password': "password", 'domain': "example.com", 'ca_cert': "auth_serv/ca.pem", - 'roaming_consortium': "112233", + 'home_ois': ["112233"], 'eap': "PEAP"}) interworking_select(dev[0], bssid, freq="2412", no_match=True) @@ -1205,10 +1205,10 @@ def test_ap_hs20_roaming_consortium_constraints(dev, apdev): 'password': "password", 'domain': "example.com", 'ca_cert': "auth_serv/ca.pem", - 'roaming_consortium': "fedcba", + 'home_ois': ["fedcba"], 'eap': "TTLS"} vals2 = vals.copy() - vals2['required_roaming_consortium'] = "223344" + vals2['required_home_ois'] = ["223344"] id = dev[0].add_cred_values(vals2) interworking_select(dev[0], bssid, "home", freq="2412", no_match=True) dev[0].remove_cred(id) @@ -1249,16 +1249,16 @@ def test_ap_hs20_roaming_consortium_constraints(dev, apdev): dev[0].remove_cred(id) values = default_cred() - values['roaming_consortium'] = "fedcba" + values['home_ois'] = ["fedcba"] id3 = dev[0].add_cred_values(values) vals2 = vals.copy() - vals2['roaming_consortium'] = "fedcba" + vals2['home_ois'] = ["fedcba"] vals2['priority'] = "2" id = dev[0].add_cred_values(vals2) values = default_cred() - values['roaming_consortium'] = "fedcba" + values['home_ois'] = ["fedcba"] id2 = dev[0].add_cred_values(values) dev[0].request("INTERWORKING_SELECT freq=2412") @@ -1285,7 +1285,7 @@ def test_ap_hs20_3gpp_constraints(dev, apdev): 'eap': "SIM", 'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"} vals2 = vals.copy() - vals2['required_roaming_consortium'] = "223344" + vals2['required_home_ois'] = ["223344"] id = dev[0].add_cred_values(vals2) interworking_select(dev[0], bssid, "home", freq="2412", no_match=True) dev[0].remove_cred(id) @@ -1313,16 +1313,16 @@ def test_ap_hs20_3gpp_constraints(dev, apdev): dev[0].remove_cred(id) values = default_cred() - values['roaming_consortium'] = "fedcba" + values['home_ois'] = ["fedcba"] id3 = dev[0].add_cred_values(values) vals2 = vals.copy() - vals2['roaming_consortium'] = "fedcba" + vals2['home_ois'] = ["fedcba"] vals2['priority'] = "2" id = dev[0].add_cred_values(vals2) values = default_cred() - values['roaming_consortium'] = "fedcba" + values['home_ois'] = ["fedcba"] id2 = dev[0].add_cred_values(values) dev[0].request("INTERWORKING_SELECT freq=2412") @@ -1365,7 +1365,7 @@ def test_ap_hs20_connect_no_full_match(dev, apdev): 'password': "password", 'domain': "example.com", 'ca_cert': "auth_serv/ca.pem", - 'roaming_consortium': "fedcba", + 'home_ois': ["fedcba"], 'eap': "TTLS", 'min_dl_bandwidth_home': "65500"} id = dev[0].add_cred_values(vals) @@ -1779,7 +1779,7 @@ def test_ap_hs20_prefer_home(dev, apdev): values['domain'] = "example.org" policy_test(dev[0], apdev[0], values, only_one=False) -def test_ap_hs20_req_roaming_consortium(dev, apdev): +def test_ap_hs20_req_home_ois(dev, apdev): """Hotspot 2.0 required roaming consortium""" check_eap_capa(dev[0], "MSCHAPV2") params = hs20_ap_params() @@ -1791,18 +1791,18 @@ def test_ap_hs20_req_roaming_consortium(dev, apdev): hostapd.add_ap(apdev[1], params) values = default_cred() - values['required_roaming_consortium'] = "223344" + values['required_home_ois'] = ["223344"] policy_test(dev[0], apdev[1], values) - values['required_roaming_consortium'] = "112233" + values['required_home_ois'] = ["112233"] policy_test(dev[0], apdev[0], values) id = dev[0].add_cred() - dev[0].set_cred(id, "required_roaming_consortium", "112233") - dev[0].set_cred(id, "required_roaming_consortium", "112233445566778899aabbccddeeff") + dev[0].set_cred_quoted(id, "required_home_ois", "112233") + dev[0].set_cred_quoted(id, "required_home_ois", "112233445566778899aabbccddeeff") for val in ["", "1", "11", "1122", "1122334", "112233445566778899aabbccddeeff00"]: - if "FAIL" not in dev[0].request('SET_CRED {} required_roaming_consortium {}'.format(id, val)): + if "FAIL" not in dev[0].request('SET_CRED {} required_home_ois {}'.format(id, val)): raise Exception("Invalid roaming consortium value accepted: " + val) def test_ap_hs20_req_roaming_consortium_no_match(dev, apdev): @@ -1818,7 +1818,7 @@ def test_ap_hs20_req_roaming_consortium_no_match(dev, apdev): hostapd.add_ap(apdev[1], params) values = default_cred() - values['required_roaming_consortium'] = "223344" + values['required_home_ois'] = ["223344"] dev[0].hs20_enable() id = dev[0].add_cred_values(values) dev[0].request("INTERWORKING_SELECT auto freq=2412") @@ -1853,7 +1853,7 @@ def test_ap_hs20_excluded_ssid(dev, apdev): raise Exception("Excluded network not reported") values = default_cred() - values['roaming_consortium'] = "223344" + values['home_ois'] = ["223344"] values['eap'] = "TTLS" values['phase2'] = "auth=MSCHAPV2" values['excluded_ssid'] = "test-hs20" @@ -5540,7 +5540,7 @@ def test_ap_hs20_cred_with_nai_realm(dev, apdev): 'username': "test", 'password': "secret", 'domain': "example.com", - 'roaming_consortium': "112234", + 'home_ois': ["112234"], 'eap': 'TTLS'}) interworking_select(dev[0], bssid, "home", freq=2412, no_match=True) dev[0].remove_cred(id) @@ -5559,7 +5559,7 @@ def test_ap_hs20_cred_and_no_roaming_consortium(dev, apdev): 'username': "test", 'password': "secret", 'domain': "example.com", - 'roaming_consortium': "112234", + 'home_ois': ["112234"], 'eap': 'TTLS'}) interworking_select(dev[0], bssid, "home", freq=2412) @@ -5635,7 +5635,7 @@ def test_ap_hs20_no_rsn_connect(dev, apdev): 'username': "test", 'password': "secret", 'domain': "example.com", - 'roaming_consortium': "112233", + 'home_ois': ["112233"], 'eap': 'TTLS'}) interworking_select(dev[0], bssid, freq=2412, no_match=True) @@ -5655,7 +5655,7 @@ def test_ap_hs20_no_match_connect(dev, apdev): 'username': "test", 'password': "secret", 'domain': "example.org", - 'roaming_consortium': "112234", + 'home_ois': ["112234"], 'eap': 'TTLS'}) interworking_select(dev[0], bssid, freq=2412, no_match=True) @@ -5712,7 +5712,7 @@ def test_ap_hs20_anqp_invalid_gas_response(dev, apdev): 'username': "test", 'password': "secret", 'domain': "example.com", - 'roaming_consortium': "112234", + 'home_ois': ["112234"], 'eap': 'TTLS'}) dev[0].request("INTERWORKING_SELECT freq=2412") @@ -5885,7 +5885,7 @@ def test_ap_hs20_set_profile_failures(dev, apdev): wait_fail_trigger(dev[0], "GET_ALLOC_FAIL") dev[0].remove_cred(id) - id = dev[0].add_cred_values({'roaming_consortium': "112233", + id = dev[0].add_cred_values({'home_ois': ["112233"], 'domain': "example.com", 'username': "hs20-test", 'password': "password", @@ -5907,7 +5907,7 @@ def test_ap_hs20_set_profile_failures(dev, apdev): dev[0].remove_cred(id) dev[0].wait_disconnected() - id = dev[0].add_cred_values({'roaming_consortium': "112233", + id = dev[0].add_cred_values({'home_ois': ["112233"], 'domain': "example.com", 'realm': "example.com", 'username': "user", @@ -5925,7 +5925,7 @@ def test_ap_hs20_set_profile_failures(dev, apdev): wait_fail_trigger(dev[0], "GET_ALLOC_FAIL") dev[0].remove_cred(id) - id = dev[0].add_cred_values({'roaming_consortium': "112233", + id = dev[0].add_cred_values({'home_ois': ["112233"], 'domain': "example.com", 'realm': "example.com", 'username': "user", @@ -5949,7 +5949,7 @@ def test_ap_hs20_set_profile_failures(dev, apdev): wait_fail_trigger(dev[0], "GET_ALLOC_FAIL") dev[0].remove_cred(id) - id = dev[0].add_cred_values({'roaming_consortium': "112233", + id = dev[0].add_cred_values({'home_ois': ["112233"], 'domain': "example.com", 'realm': "example.com", 'username': "user", @@ -6023,7 +6023,7 @@ def test_ap_hs20_set_profile_failures(dev, apdev): wait_fail_trigger(dev[0], "GET_ALLOC_FAIL") dev[0].remove_cred(id) - id = dev[0].add_cred_values({'roaming_consortium': "112233", + id = dev[0].add_cred_values({'home_ois': ["112233"], 'eap': 'TTLS', 'username': "user@xxxxxxxxxxx", 'password': "password"}) diff --git a/tests/hwsim/test_dbus.py b/tests/hwsim/test_dbus.py index fe59e1856..03968b33f 100644 --- a/tests/hwsim/test_dbus.py +++ b/tests/hwsim/test_dbus.py @@ -6104,8 +6104,8 @@ def test_dbus_creds(dev, apdev): args = {'domain': 'server.w1.fi', 'realm': 'server.w1.fi', - 'roaming_consortium': '50a9bf', - 'required_roaming_consortium': '23bf50', + 'home_ois': ['50a9bf'], + 'required_home_ois': ['23bf50'], 'eap': 'TTLS', 'phase2': 'auth=MSCHAPV2', 'username': 'user', diff --git a/tests/hwsim/test_wpas_config.py b/tests/hwsim/test_wpas_config.py index 3cd7dfcf3..860e80a05 100644 --- a/tests/hwsim/test_wpas_config.py +++ b/tests/hwsim/test_wpas_config.py @@ -223,8 +223,8 @@ def test_wpas_config_file(dev, apdev, params): wpas.set_cred_quoted(id, "provisioning_sp", "example.com") wpas.set_cred_quoted(id, "domain", "example.com") wpas.set_cred_quoted(id, "domain_suffix_match", "example.com") - wpas.set_cred(id, "roaming_consortium", "112233") - wpas.set_cred(id, "required_roaming_consortium", "112233") + wpas.set_cred_quoted(id, "home_ois", "112233,445566") + wpas.set_cred_quoted(id, "required_home_ois", "112233") wpas.set_cred_quoted(id, "roaming_consortiums", "112233,aabbccddee,445566") wpas.set_cred_quoted(id, "roaming_partner", diff --git a/tests/hwsim/test_wpas_ctrl.py b/tests/hwsim/test_wpas_ctrl.py index 898e8bdea..ea560a89a 100644 --- a/tests/hwsim/test_wpas_ctrl.py +++ b/tests/hwsim/test_wpas_ctrl.py @@ -465,8 +465,12 @@ def test_wpas_ctrl_cred(dev): raise Exception("Unexpected success on invalid string") for i in ("11", "1122", "112233445566778899aabbccddeeff00"): - if "FAIL" not in dev[0].request("SET_CRED " + str(id) + " roaming_consortium " + i): - raise Exception("Unexpected success on invalid roaming_consortium") + if "FAIL" not in dev[0].request("SET_CRED " + str(id) + " home_ois " + i): + raise Exception("Unexpected success on invalid home_ois") + + for i in ("11", "1122", "112233445566778899aabbccddeeff00"): + if "FAIL" not in dev[0].request("SET_CRED " + str(id) + " required_home_ois " + i): + raise Exception("Unexpected success on invalid required_home_ois") dev[0].set_cred(id, "excluded_ssid", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff") if "FAIL" not in dev[0].request("SET_CRED " + str(id) + " excluded_ssid 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00"): diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py index fe1892785..adc7e02e7 100644 --- a/tests/hwsim/wpasupplicant.py +++ b/tests/hwsim/wpasupplicant.py @@ -460,15 +460,19 @@ class WpaSupplicant: if field in params: self.set_cred_quoted(id, field, params[field]) - not_quoted = ["eap", "roaming_consortium", "priority", - "required_roaming_consortium", "sp_priority", - "max_bss_load", "update_identifier", "req_conn_capab", + not_quoted = ["eap", "priority", "sp_priority", "max_bss_load", + "update_identifier", "req_conn_capab", "min_dl_bandwidth_home", "min_ul_bandwidth_home", "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming"] for field in not_quoted: if field in params: self.set_cred(id, field, params[field]) + as_list = ["home_ois", "required_home_ois"] + for field in as_list: + if field in params: + self.set_cred_quoted(id, field, ','.join(params[field])) + return id def select_network(self, id, freq=None): diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a91c689d0..c1dd66bcf 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3531,53 +3531,61 @@ static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred, } -static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred, - const char *value) -{ - u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; - size_t roaming_consortiums_len[MAX_ROAMING_CONS]; - unsigned int num_roaming_consortiums = 0; +static int wpa_config_set_cred_ois(u8 cred_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN], + size_t cred_ois_len[MAX_ROAMING_CONS], + unsigned int *cred_num_ois, + const char *value) +{ + u8 ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; + size_t ois_len[MAX_ROAMING_CONS]; + unsigned int num_ois = 0; const char *pos, *end; size_t len; - os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums)); - os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len)); + len = os_strlen(value); + if (len / 2 < 3) { + wpa_printf(MSG_ERROR, + "Invalid organisation identifier (OI) list: %s", + value); + return -1; + } + + os_memset(ois, 0, sizeof(ois)); + os_memset(ois_len, 0, sizeof(ois_len)); for (pos = value;;) { end = os_strchr(pos, ','); len = end ? (size_t) (end - pos) : os_strlen(pos); if (!end && len == 0) break; - if (len == 0 || (len & 1) != 0 || + if (len / 2 < 3 || (len & 1) != 0 || len / 2 > MAX_ROAMING_CONS_OI_LEN || hexstr2bin(pos, - roaming_consortiums[num_roaming_consortiums], + ois[num_ois], len / 2) < 0) { - wpa_printf(MSG_INFO, - "Invalid roaming_consortiums entry: %s", + wpa_printf(MSG_ERROR, + "Invalid organisation identifier (OI) entry: %s", pos); return -1; } - roaming_consortiums_len[num_roaming_consortiums] = len / 2; - num_roaming_consortiums++; + ois_len[num_ois] = len / 2; + num_ois++; if (!end) break; - if (num_roaming_consortiums >= MAX_ROAMING_CONS) { + if (num_ois >= MAX_ROAMING_CONS) { wpa_printf(MSG_INFO, - "Too many roaming_consortiums OIs"); + "Too many OIs"); return -1; } pos = end + 1; } - os_memcpy(cred->roaming_consortiums, roaming_consortiums, - sizeof(roaming_consortiums)); - os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len, - sizeof(roaming_consortiums_len)); - cred->num_roaming_consortiums = num_roaming_consortiums; + os_memcpy(cred_ois, ois, sizeof(ois)); + os_memcpy(cred_ois_len, ois_len, sizeof(ois_len)); + *cred_num_ois = num_ois; return 0; } @@ -3812,21 +3820,25 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, } if (os_strcmp(var, "roaming_consortium") == 0) { - if (len < 3 || len > sizeof(cred->roaming_consortium)) { + if (len < 3 || len > sizeof(cred->home_ois[0])) { 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; + wpa_printf(MSG_WARNING, "Line %d: option roaming_consortium is " + "deprecated and will be removed in the future", + line); + os_memcpy(cred->home_ois[0], val, len); + cred->home_ois_len[0] = len; + cred->num_home_ois = 1; os_free(val); return 0; } if (os_strcmp(var, "required_roaming_consortium") == 0) { - if (len < 3 || len > sizeof(cred->required_roaming_consortium)) + if (len < 3 || len > sizeof(cred->required_home_ois[0])) { wpa_printf(MSG_ERROR, "Line %d: invalid " "required_roaming_consortium length %d " @@ -3834,14 +3846,48 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, os_free(val); return -1; } - os_memcpy(cred->required_roaming_consortium, val, len); - cred->required_roaming_consortium_len = len; + wpa_printf(MSG_WARNING, + "Line %d: option required_roaming_consortium is " + "deprecated and will be removed in the future", + line); + os_memcpy(cred->required_home_ois[0], val, len); + cred->required_home_ois_len[0] = len; + cred->num_required_home_ois = 1; os_free(val); return 0; } + if (os_strcmp(var, "home_ois") == 0) { + res = wpa_config_set_cred_ois(cred->home_ois, + cred->home_ois_len, + &cred->num_home_ois, + val); + if (res < 0) + wpa_printf(MSG_ERROR, + "Line %d: invalid home_ois", + line); + os_free(val); + return res; + } + + if (os_strcmp(var, "required_home_ois") == 0) { + res = wpa_config_set_cred_ois(cred->required_home_ois, + cred->required_home_ois_len, + &cred->num_required_home_ois, + val); + if (res < 0) + wpa_printf(MSG_ERROR, + "Line %d: invalid required_home_ois", + line); + os_free(val); + return res; + } + if (os_strcmp(var, "roaming_consortiums") == 0) { - res = wpa_config_set_cred_roaming_consortiums(cred, val); + res = wpa_config_set_cred_ois(cred->roaming_consortiums, + cred->roaming_consortiums_len, + &cred->num_roaming_consortiums, + val); if (res < 0) wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortiums", @@ -4153,14 +4199,14 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) size_t buflen; char *buf; - if (!cred->roaming_consortium_len) + if (!cred->num_home_ois || !cred->home_ois_len[0]) return NULL; - buflen = cred->roaming_consortium_len * 2 + 1; + buflen = cred->home_ois_len[0] * 2 + 1; buf = os_malloc(buflen); if (buf == NULL) return NULL; - wpa_snprintf_hex(buf, buflen, cred->roaming_consortium, - cred->roaming_consortium_len); + wpa_snprintf_hex(buf, buflen, cred->home_ois[0], + cred->home_ois_len[0]); return buf; } @@ -4168,14 +4214,65 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) size_t buflen; char *buf; - if (!cred->required_roaming_consortium_len) + if (!cred->num_required_home_ois || + !cred->required_home_ois_len[0]) return NULL; - buflen = cred->required_roaming_consortium_len * 2 + 1; + buflen = cred->required_home_ois_len[0] * 2 + 1; buf = os_malloc(buflen); if (buf == NULL) return NULL; - wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium, - cred->required_roaming_consortium_len); + wpa_snprintf_hex(buf, buflen, cred->required_home_ois[0], + cred->required_home_ois_len[0]); + return buf; + } + + if (os_strcmp(var, "home_ois") == 0) { + size_t buflen; + char *buf, *pos; + size_t i; + + if (!cred->num_home_ois) + return NULL; + buflen = cred->num_home_ois * + MAX_ROAMING_CONS_OI_LEN * 2 + 1; + buf = os_malloc(buflen); + if (!buf) + return NULL; + pos = buf; + for (i = 0; i < cred->num_home_ois; i++) { + if (i > 0) + *pos++ = ','; + pos += wpa_snprintf_hex( + pos, buf + buflen - pos, + cred->home_ois[i], + cred->home_ois_len[i]); + } + *pos = '\0'; + return buf; + } + + if (os_strcmp(var, "required_home_ois") == 0) { + size_t buflen; + char *buf, *pos; + size_t i; + + if (!cred->num_required_home_ois) + return NULL; + buflen = cred->num_required_home_ois * + MAX_ROAMING_CONS_OI_LEN * 2 + 1; + buf = os_malloc(buflen); + if (!buf) + return NULL; + pos = buf; + for (i = 0; i < cred->num_required_home_ois; i++) { + if (i > 0) + *pos++ = ','; + pos += wpa_snprintf_hex( + pos, buf + buflen - pos, + cred->required_home_ois[i], + cred->required_home_ois_len[i]); + } + *pos = '\0'; return buf; } diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 8b8be2a45..d509074be 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -259,36 +259,50 @@ struct wpa_cred { size_t num_domain; /** - * roaming_consortium - Roaming Consortium OI + * home_ois - Home OIs * - * 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. + * If num_home_ois is non-zero, this field contains the set of Home OIs + * that can be use to determine which access points support + * authentication with this credential. There are an alternative to the + * use of the realm parameter. When using Home OIs to match the network, + * the EAP parameters need to be pre-configured with the credentials + * since the NAI Realm information may not be available or fetched. + * A successful authentication with the access point is possible as soon + * as at least one Home OI from the list matches an OI in the Roaming + * Consortium advertised by the access point. + * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOI) */ - u8 roaming_consortium[15]; + u8 home_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; /** - * roaming_consortium_len - Length of roaming_consortium + * home_ois_len - Length of home_ois[i] */ - size_t roaming_consortium_len; + size_t home_ois_len[MAX_ROAMING_CONS]; /** - * required_roaming_consortium - Required Roaming Consortium OI + * num_home_ois - Number of entries in home_ois + */ + unsigned int num_home_ois; + + /** + * required_home_ois - Required Home OI(s) * - * If required_roaming_consortium_len is non-zero, this field contains - * the Roaming Consortium OI that is required to be advertised by the AP - * for the credential to be considered matching. + * If required_home_ois_len is non-zero, this field contains the set of + * Home OI(s) that are required to be advertised by the AP for the + * credential to be considered matching. + * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOIRequired) + */ + u8 required_home_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; + + /** + * required_home_ois_len - Length of required_home_ois */ - u8 required_roaming_consortium[15]; + size_t required_home_ois_len[MAX_ROAMING_CONS]; /** - * required_roaming_consortium_len - Length of required_roaming_consortium + * num_required_home_ois - Number of entries in required_home_ois */ - size_t required_roaming_consortium_len; + unsigned int num_required_home_ois; /** * roaming_consortiums - Roaming Consortium OI(s) memberships diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index b637dbfbc..51b8d05f8 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -921,12 +921,6 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) if (cred->domain_suffix_match) fprintf(f, "\tdomain_suffix_match=\"%s\"\n", cred->domain_suffix_match); - if (cred->roaming_consortium_len) { - fprintf(f, "\troaming_consortium="); - for (i = 0; i < cred->roaming_consortium_len; i++) - fprintf(f, "%02x", cred->roaming_consortium[i]); - fprintf(f, "\n"); - } if (cred->eap_method) { const char *name; name = eap_get_name(cred->eap_method[0].vendor, @@ -1002,12 +996,32 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) } } - if (cred->required_roaming_consortium_len) { - fprintf(f, "\trequired_roaming_consortium="); - for (i = 0; i < cred->required_roaming_consortium_len; i++) - fprintf(f, "%02x", - cred->required_roaming_consortium[i]); - fprintf(f, "\n"); + if (cred->num_home_ois) { + size_t j; + + fprintf(f, "\thome_ois=\""); + for (i = 0; i < cred->num_home_ois; i++) { + if (i > 0) + fprintf(f, ","); + for (j = 0; j < cred->home_ois_len[i]; j++) + fprintf(f, "%02x", + cred->home_ois[i][j]); + } + fprintf(f, "\"\n"); + } + + if (cred->num_required_home_ois) { + size_t j; + + fprintf(f, "\trequired_home_ois=\""); + for (i = 0; i < cred->num_required_home_ois; i++) { + if (i > 0) + fprintf(f, ","); + for (j = 0; j < cred->required_home_ois_len[i]; j++) + fprintf(f, "%02x", + cred->required_home_ois[i][j]); + } + fprintf(f, "\"\n"); } if (cred->num_roaming_consortiums) { diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index bc81728ad..7fd2082f6 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -144,9 +144,9 @@ static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { - if (cred->roaming_consortium_len) + if (cred->num_home_ois) return 1; - if (cred->required_roaming_consortium_len) + if (cred->num_required_home_ois) return 1; if (cred->num_roaming_consortiums) return 1; @@ -1092,8 +1092,7 @@ fail: } -static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, - size_t rc_len) +static int oi_element_match(const u8 *ie, const u8 *oi, size_t oi_len) { const u8 *pos, *end; u8 lens; @@ -1118,24 +1117,24 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, if ((lens & 0x0f) + (lens >> 4) > end - pos) return 0; - if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + if ((lens & 0x0f) == oi_len && os_memcmp(pos, oi, oi_len) == 0) return 1; pos += lens & 0x0f; - if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + if ((lens >> 4) == oi_len && os_memcmp(pos, oi, oi_len) == 0) return 1; pos += lens >> 4; - if (pos < end && (size_t) (end - pos) == rc_len && - os_memcmp(pos, rc_id, rc_len) == 0) + if (pos < end && (size_t) (end - pos) == oi_len && + os_memcmp(pos, oi, oi_len) == 0) return 1; return 0; } -static int roaming_consortium_anqp_match(const struct wpabuf *anqp, - const u8 *rc_id, size_t rc_len) +static int oi_anqp_match(const struct wpabuf *anqp, const u8 *oi, + size_t oi_len) { const u8 *pos, *end; u8 len; @@ -1151,7 +1150,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, len = *pos++; if (len > end - pos) break; - if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + if (len == oi_len && os_memcmp(pos, oi, oi_len) == 0) return 1; pos += len; } @@ -1160,13 +1159,26 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, } -static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, - const u8 *rc_id, size_t rc_len) +static int oi_match(const u8 *ie, const struct wpabuf *anqp, + const u8 *oi, size_t oi_len) { - return roaming_consortium_element_match(ie, rc_id, rc_len) || - roaming_consortium_anqp_match(anqp, rc_id, rc_len); + return oi_element_match(ie, oi, oi_len) || + oi_anqp_match(anqp, oi, oi_len); } +static int cred_home_ois_match(const u8 *ie, const struct wpabuf *anqp, + const struct wpa_cred *cred) { + unsigned int i; + + // There's a match if at least one of the home OI matches. + for (i = 0; i < cred->num_home_ois; i++) { + if (oi_match(ie, anqp, cred->home_ois[i], + cred->home_ois_len[i])) + return 1; + } + + return 0; +} static int cred_roaming_consortiums_match(const u8 *ie, const struct wpabuf *anqp, @@ -1175,9 +1187,8 @@ static int cred_roaming_consortiums_match(const u8 *ie, unsigned int i; for (i = 0; i < cred->num_roaming_consortiums; i++) { - if (roaming_consortium_match(ie, anqp, - cred->roaming_consortiums[i], - cred->roaming_consortiums_len[i])) + if (oi_match(ie, anqp, cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) return 1; } @@ -1188,8 +1199,9 @@ static int cred_roaming_consortiums_match(const u8 *ie, static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) { const u8 *ie; + unsigned int i; - if (cred->required_roaming_consortium_len == 0) + if (cred->num_required_home_ois == 0) return 0; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); @@ -1198,11 +1210,16 @@ static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) return 1; - return !roaming_consortium_match(ie, - bss->anqp ? - bss->anqp->roaming_consortium : NULL, - cred->required_roaming_consortium, - cred->required_roaming_consortium_len); + // According to Passpoint specification, there must be a match for + // each required home OI provided. + for (i = 0; i < cred->num_required_home_ois; i++) { + if (!oi_match(ie, bss->anqp ? + bss->anqp->roaming_consortium : NULL, + cred->required_home_ois[i], + cred->required_home_ois_len[i])) + return 1; + } + return 0; } @@ -1402,26 +1419,24 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium( return NULL; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { - if (cred->roaming_consortium_len == 0 && + if (cred->num_home_ois == 0 && + cred->num_required_home_ois == 0 && cred->num_roaming_consortiums == 0) continue; if (!cred->eap_method) continue; - if ((cred->roaming_consortium_len == 0 || - !roaming_consortium_match(ie, anqp, - cred->roaming_consortium, - cred->roaming_consortium_len)) && - !cred_roaming_consortiums_match(ie, anqp, cred) && - (cred->required_roaming_consortium_len == 0 || - !roaming_consortium_match( - ie, anqp, cred->required_roaming_consortium, - cred->required_roaming_consortium_len))) + // If there's required home OIs, there must be a match for each + // required OI (see Passpoint v3.2 - §9.1.2 - RequiredHomeOI). + if (cred->num_required_home_ois > 0 && + cred_no_required_oi_match(cred, bss)) continue; - if (cred_no_required_oi_match(cred, bss)) + if (!cred_home_ois_match(ie, anqp, cred) && + !cred_roaming_consortiums_match(ie, anqp, cred)) continue; + if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss)) @@ -1636,9 +1651,8 @@ static int interworking_connect_roaming_consortium( ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL; for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) { - if (!roaming_consortium_match( - ie, anqp, cred->roaming_consortiums[i], - cred->roaming_consortiums_len[i])) + if (!oi_match(ie, anqp, cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) continue; ssid->roaming_consortium_selection = diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 90061ba67..d0c28c025 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -655,7 +655,26 @@ fast_reauth=1 # be used to configure alternative FQDNs that will be considered home # networks. # +# home_ois: Home OI(s) +# This string field contains one or more comma delimited OIs (hexdump) +# identifying the access the access points that support authentication +# with this credential. There are an alternative to the use of the realm +# parameter. When using Home OIs to match the network, the EAP parameters +# need to be pre-configured with the credentials since the NAI Realm +# information may not be available or fetched. +# A successful authentication with the access point is possible as soon +# as at least one Home OI from the list matches an OI in the Roaming +# Consortium advertised by the access point. +# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOI) +# +# required_home_ois: Required Home OI(s) +# This string field contains the set of Home OI(s) (hexdump) that are +# required to be advertised by the AP for the credential to be considered +# matching. +# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOIRequired) +# # roaming_consortium: Roaming Consortium OI +# Deprecated: use home_ois instead. # 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 @@ -665,6 +684,7 @@ fast_reauth=1 # may not be available or fetched. # # required_roaming_consortium: Required Roaming Consortium OI +# Deprecated: use required_home_ois instead. # If required_roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that is required to be advertised by the AP for # the credential to be considered matching. -- 2.37.2.789.g6183377224-goog _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap