From patchwork Mon Sep 12 11:49:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Damien Dejean X-Patchwork-Id: 1676927 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=rqrdGjE2; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=oAKSsicQ; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4MR4g02JSKz1ypL for ; Mon, 12 Sep 2022 21:50:52 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=Fqi9e+x0VnRlnsFuGKKWZwe7FaAXlht76mQ2suaJIvQ=; b=rqrdGjE28D62ds Aa3gfAAq93o/uX2mtadUugHX8Nd/2HwwQcPoZslCIx1IdUd6aXxPix+TiXc8k/VmZrxZmvpp8cnyQ 9RSngEh805NtuTrT32lDnY18Zk/pu5UeYFAesWvexxrIfy/q+Nud42yY2YHAXwszbg3tsoZOy1G51 Pf6EnSHPI6NEvH8TYF9mmHYHr/xYxbgbNpzrlZa7kD6qQIdrShTq2h5qhFJJ1HWGVAbkSgqxYb3Ix vhAJUl+2IozTY9LSl79/yZOXIVp0Uk+nm/czdIQAUirhK0v6iZ10ZONWrxY+nRWED+4fWY5mvqLRF o5sIvDqLb5+LuYR2neiA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oXhwZ-009SYy-2S; Mon, 12 Sep 2022 11:49:39 +0000 Received: from mail-wr1-x433.google.com ([2a00:1450:4864:20::433]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1oXhwS-009SV4-G8 for hostap@lists.infradead.org; Mon, 12 Sep 2022 11:49:36 +0000 Received: by mail-wr1-x433.google.com with SMTP id d2so14950714wrn.1 for ; Mon, 12 Sep 2022 04:49:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date; bh=gfaFjc6pDbtz2C6Q9PrLhNa4CGUwyW+lCiep+ypXQ/c=; b=oAKSsicQiKWrN99Kwv7InmQlKMjLtBod3lijmyOX3oIHhheWLq6iHxXbExIEPuvZGN 7g1g+lQVX7YPYjSWY4dsLoc3v8Os7+xM+K4m+Q8qMuI+JTMrZIblcuikjDSRhQv67GkI i0Cjb9Tr5zKytnM09kU7HaBUZSG37/F5Z1450= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date; bh=gfaFjc6pDbtz2C6Q9PrLhNa4CGUwyW+lCiep+ypXQ/c=; b=uYxMfRJoJBeo05fyM0sAw/7KM/gZvWu8xqR8nE27q0dsvbVf/5SbG8etD3Vl+Gk04/ jLGNAolpRxC4ykzMXVPhz+a9XvIhQHBgQTXV/ZjBZfRQSdVboKZimrRW48Ej/iFAuw21 r4VeqbPq5DbnlN462E7/uho49jM3ErzGVLjeyZn4lCHglGprg/dK1AxrSZeYJ/QrLmOt iu+QtI7q4iluy8brKc8tq4gG1M0kKeL1h7/scqghvSkIhCKR8HliAsh8PyY+FOAXG5Je iJDn9cktXnDTTj7ZtxB8OyRcPDLNFaQDqW0RayZmSaMbab729SBB+f96k9/pPFpFAxUs JqFQ== X-Gm-Message-State: ACgBeo1J3Q7ZsPrzok4QbQ/wtoxkETqBHd4fE0BBvxGK36o8Gk3slYSL micvMgto7L3UD64Xs3KzI6hGkNkffDaiBDpr X-Google-Smtp-Source: AA6agR70kIizIqdiHFYeVhqwsVQYaeHgo7K1przN0u7/4y0QC7f63e/mmB3IxZIlPVLYH6lLNZZRpg== X-Received: by 2002:a05:6000:1888:b0:22a:4868:6048 with SMTP id a8-20020a056000188800b0022a48686048mr6544667wri.32.1662983368799; Mon, 12 Sep 2022 04:49:28 -0700 (PDT) Received: from ddejean-chromeos.c.googlers.com.com (88.140.78.34.bc.googleusercontent.com. [34.78.140.88]) by smtp.gmail.com with ESMTPSA id q15-20020a1ce90f000000b003a2f2bb72d5sm11372945wmc.45.2022.09.12.04.49.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Sep 2022 04:49:28 -0700 (PDT) From: Damien Dejean To: hostap@lists.infradead.org Cc: Damien Dejean Subject: [PATCH] HS20: support credentials with multiple home OIs Date: Mon, 12 Sep 2022 11:49:09 +0000 Message-Id: <20220912114909.2962404-1-damiendejean@chromium.org> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220912_044932_795339_58435014 X-CRM114-Status: GOOD ( 14.77 ) X-Spam-Score: 0.1 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: 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 P [...] Content analysis details: (0.1 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2a00:1450:4864:20:0:0:0:433 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.5 PDS_BTC_ID FP reduced Bitcoin ID -0.2 DKIMWL_WL_HIGH DKIMwl.org - High trust sender X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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//HomeSP/HomeOIList/). Signed-off-by: Damien Dejean --- 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 | 5 + 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, 313 insertions(+), 145 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@example.com", '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..b3507ea58 100644 --- a/tests/hwsim/wpasupplicant.py +++ b/tests/hwsim/wpasupplicant.py @@ -469,6 +469,11 @@ class WpaSupplicant: 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//HomeSP/HomeOIList//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//HomeSP/HomeOIList//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//HomeSP/HomeOIList//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//HomeSP/HomeOIList//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.