From 4354285b8de3345d5146f68ce2d17be83b4f34a4 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Wed, 11 Mar 2020 13:57:36 -0700 Subject: [Passpoint] Fix Passpoint matching algorithm for Home networks Match Home networks if there is an FQDN match (without realm or method), or if OtherHomePartners element exists and matches the other advertised FQDNs, or if HomeOIList element exists and matches advertised RCOIs. Bug: 151245024 Test: atest PasspointProviderTest ANQPMatcherTest Change-Id: I7bf9c98c853c3973d30ce2651bdea49546dae4b5 Merged-In: I513f83a6d545b9ae7da5577ee163ce7d186f006e --- .../android/server/wifi/hotspot2/ANQPMatcher.java | 63 ++----- .../server/wifi/hotspot2/PasspointManager.java | 6 + .../server/wifi/hotspot2/PasspointProvider.java | 174 +++++++++++++++---- .../server/wifi/hotspot2/ANQPMatcherTest.java | 127 ++++++++------ .../wifi/hotspot2/PasspointProviderTest.java | 189 ++++++++++++++++++++- 5 files changed, 421 insertions(+), 138 deletions(-) diff --git a/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java b/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java index d95ab3831..69f98b0ef 100644 --- a/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java +++ b/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java @@ -75,10 +75,11 @@ public class ANQPMatcher { * * @param element The Roaming Consortium ANQP element * @param providerOIs The roaming consortium OIs of the provider + * @param matchAll Indicates if a match with all OIs must be done * @return true if a match is found */ public static boolean matchRoamingConsortium(RoamingConsortiumElement element, - long[] providerOIs) { + long[] providerOIs, boolean matchAll) { if (element == null) { return false; } @@ -88,10 +89,14 @@ public class ANQPMatcher { List rcOIs = element.getOIs(); for (long oi : providerOIs) { if (rcOIs.contains(oi)) { - return true; + if (!matchAll) { + return true; + } + } else if (matchAll) { + return false; } } - return false; + return matchAll; } /** @@ -100,27 +105,19 @@ public class ANQPMatcher { * * @param element The NAI Realm ANQP element * @param realm The realm of the provider's credential - * @param eapMethodID The EAP Method ID of the provider's credential - * @param authParam The authentication parameter of the provider's credential * @return an integer indicating the match status */ - public static int matchNAIRealm(NAIRealmElement element, String realm, int eapMethodID, - AuthParam authParam) { + public static boolean matchNAIRealm(NAIRealmElement element, String realm) { if (element == null || element.getRealmDataList().isEmpty()) { - return AuthMatch.INDETERMINATE; + return false; } - int bestMatch = AuthMatch.NONE; for (NAIRealmData realmData : element.getRealmDataList()) { - int match = matchNAIRealmData(realmData, realm, eapMethodID, authParam); - if (match > bestMatch) { - bestMatch = match; - if (bestMatch == AuthMatch.EXACT) { - break; - } + if (matchNAIRealmData(realmData, realm)) { + return true; } } - return bestMatch; + return false; } /** @@ -172,42 +169,16 @@ public class ANQPMatcher { * * @param realmData The NAI Realm data * @param realm The realm of the provider's credential - * @param eapMethodID The EAP Method ID of the provider's credential - * @param authParam The authentication parameter of the provider's credential - * @return an integer indicating the match status + * @return true if a match is found */ - private static int matchNAIRealmData(NAIRealmData realmData, String realm, int eapMethodID, - AuthParam authParam) { + private static boolean matchNAIRealmData(NAIRealmData realmData, String realm) { // Check for realm domain name match. - int realmMatch = AuthMatch.NONE; for (String realmStr : realmData.getRealms()) { if (DomainMatcher.arg2SubdomainOfArg1(realm, realmStr)) { - realmMatch = AuthMatch.REALM; - break; - } - } - - if (realmData.getEAPMethods().isEmpty()) { - return realmMatch; - } - - // Check for EAP method match. - int eapMethodMatch = AuthMatch.NONE; - for (EAPMethod eapMethod : realmData.getEAPMethods()) { - eapMethodMatch = matchEAPMethod(eapMethod, eapMethodID, authParam); - if (eapMethodMatch != AuthMatch.NONE) { - break; + return true; } } - - if (eapMethodMatch == AuthMatch.NONE) { - return AuthMatch.NONE; - } - - if (realmMatch == AuthMatch.NONE) { - return eapMethodMatch; - } - return realmMatch | eapMethodMatch; + return false; } private static int getEapMethodForNAIRealmWithCarrier(String realm, diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java index c46873761..172d1a13d 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java @@ -217,6 +217,7 @@ public class PasspointManager { public void setProviders(List providers) { mProviders.clear(); for (PasspointProvider provider : providers) { + provider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0); mProviders.put(provider.getConfig().getHomeSp().getFqdn(), provider); if (provider.getPackageName() != null) { startTrackingAppOpsChange(provider.getPackageName(), @@ -377,6 +378,9 @@ public class PasspointManager { public void enableVerboseLogging(int verbose) { mVerboseLoggingEnabled = (verbose > 0) ? true : false; mPasspointProvisioner.enableVerboseLogging(verbose); + for (PasspointProvider provider : mProviders.values()) { + provider.enableVerboseLogging(verbose); + } } /** @@ -433,6 +437,7 @@ public class PasspointManager { mProviders.get(config.getHomeSp().getFqdn()).uninstallCertsAndKeys(); mProviders.remove(config.getHomeSp().getFqdn()); } + newProvider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0); mProviders.put(config.getHomeSp().getFqdn(), newProvider); mWifiConfigManager.saveToStore(true /* forceWrite */); if (newProvider.getPackageName() != null) { @@ -1165,6 +1170,7 @@ public class PasspointManager { Arrays.asList(enterpriseConfig.getCaCertificateAlias()), enterpriseConfig.getClientCertificateAlias(), enterpriseConfig.getClientCertificateAlias(), null, false, false); + provider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0); mProviders.put(passpointConfig.getHomeSp().getFqdn(), provider); return true; } diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java index ca9814aa6..8db71d3e6 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java @@ -95,6 +95,7 @@ public class PasspointProvider { private boolean mHasEverConnected; private boolean mIsShared; + private boolean mVerboseLoggingEnabled; /** * This is a flag to indicate if the Provider is created temporarily. @@ -327,39 +328,53 @@ public class PasspointProvider { * Return the matching status with the given AP, based on the ANQP elements from the AP. * * @param anqpElements ANQP elements from the AP - * @param roamingConsortium Roaming Consortium information element from the AP + * @param roamingConsortiumFromAp Roaming Consortium information element from the AP * @return {@link PasspointMatch} */ public PasspointMatch match(Map anqpElements, - RoamingConsortium roamingConsortium) { - PasspointMatch providerMatch = matchProviderExceptFor3GPP(anqpElements, roamingConsortium); + RoamingConsortium roamingConsortiumFromAp) { + // Match FQDN for Home provider or RCOI(s) for Roaming provider + // For SIM credential, the FQDN is in the format of wlan.mnc*.mcc*.3gppnetwork.org + PasspointMatch providerMatch = matchFqdnAndRcoi(anqpElements, roamingConsortiumFromAp); // 3GPP Network matching. if (providerMatch == PasspointMatch.None && ANQPMatcher.matchThreeGPPNetwork( (ThreeGPPNetworkElement) anqpElements.get(ANQPElementType.ANQP3GPPNetwork), mImsiParameter, mMatchingSIMImsiList)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Final RoamingProvider match with " + + anqpElements.get(ANQPElementType.ANQP3GPPNetwork)); + } return PasspointMatch.RoamingProvider; } - // Perform authentication match against the NAI Realm. - int authMatch = ANQPMatcher.matchNAIRealm( + // Perform NAI Realm matching + boolean realmMatch = ANQPMatcher.matchNAIRealm( (NAIRealmElement) anqpElements.get(ANQPElementType.ANQPNAIRealm), - mConfig.getCredential().getRealm(), mEAPMethodID, mAuthParam); - - // In case of Auth mismatch, demote provider match. - if (authMatch == AuthMatch.NONE) { - return PasspointMatch.None; - } + mConfig.getCredential().getRealm()); // In case of no realm match, return provider match as is. - if ((authMatch & AuthMatch.REALM) == 0) { + if (!realmMatch) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "No NAI realm match, final match: " + providerMatch); + } return providerMatch; } - // Promote the provider match to roaming provider if provider match is not found, but NAI + if (mVerboseLoggingEnabled) { + Log.d(TAG, "NAI realm match with " + mConfig.getCredential().getRealm()); + } + + // Promote the provider match to RoamingProvider if provider match is not found, but NAI // realm is matched. - return providerMatch == PasspointMatch.None ? PasspointMatch.RoamingProvider - : providerMatch; + if (providerMatch == PasspointMatch.None) { + providerMatch = PasspointMatch.RoamingProvider; + } + + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Final match: " + providerMatch); + } + return providerMatch; } /** @@ -569,43 +584,130 @@ public class PasspointProvider { || passpointConfig.getUsageLimitTimeLimitInMinutes() > 0; } + /** + * Match given OIs to the Roaming Consortium OIs + * + * @param providerOis Provider OIs to match against + * @param roamingConsortiumElement RCOIs in the ANQP element + * @param roamingConsortiumFromAp RCOIs in the AP scan results + * @param matchAll Indicates if all providerOis must match the RCOIs elements + * @return {@code true} if there is a match, {@code false} otherwise. + */ + private boolean matchOis(long[] providerOis, + RoamingConsortiumElement roamingConsortiumElement, + RoamingConsortium roamingConsortiumFromAp, + boolean matchAll) { + + + // ANQP Roaming Consortium OI matching. + if (ANQPMatcher.matchRoamingConsortium(roamingConsortiumElement, providerOis, matchAll)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "ANQP RCOI match " + roamingConsortiumElement); + } + return true; + } + + // AP Roaming Consortium OI matching. + long[] apRoamingConsortiums = roamingConsortiumFromAp.getRoamingConsortiums(); + if (apRoamingConsortiums == null || providerOis == null) { + return false; + } + // Roaming Consortium OI information element matching. + for (long apOi: apRoamingConsortiums) { + boolean matched = false; + for (long providerOi: providerOis) { + if (apOi == providerOi) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "AP RCOI match: " + apOi); + } + if (!matchAll) { + return true; + } else { + matched = true; + break; + } + } + } + if (matchAll && !matched) { + return false; + } + } + return matchAll; + } + /** * Perform a provider match based on the given ANQP elements except for matching 3GPP Network. * * @param anqpElements List of ANQP elements - * @param roamingConsortium Roaming Consortium information element from the AP + * @param roamingConsortiumFromAp Roaming Consortium information element from the AP * @return {@link PasspointMatch} */ - private PasspointMatch matchProviderExceptFor3GPP( + private PasspointMatch matchFqdnAndRcoi( Map anqpElements, - RoamingConsortium roamingConsortium) { + RoamingConsortium roamingConsortiumFromAp) { // Domain name matching. if (ANQPMatcher.matchDomainName( (DomainNameElement) anqpElements.get(ANQPElementType.ANQPDomName), mConfig.getHomeSp().getFqdn(), mImsiParameter, mMatchingSIMImsiList)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Domain name " + mConfig.getHomeSp().getFqdn() + + " match: HomeProvider"); + } return PasspointMatch.HomeProvider; } - // ANQP Roaming Consortium OI matching. - long[] providerOIs = mConfig.getHomeSp().getRoamingConsortiumOis(); - if (ANQPMatcher.matchRoamingConsortium( - (RoamingConsortiumElement) anqpElements.get(ANQPElementType.ANQPRoamingConsortium), - providerOIs)) { - return PasspointMatch.RoamingProvider; + // Other Home Partners matching. + if (mConfig.getHomeSp().getOtherHomePartners() != null) { + for (String otherHomePartner : mConfig.getHomeSp().getOtherHomePartners()) { + if (ANQPMatcher.matchDomainName( + (DomainNameElement) anqpElements.get(ANQPElementType.ANQPDomName), + otherHomePartner, null, null)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Other Home Partner " + otherHomePartner + + " match: HomeProvider"); + } + return PasspointMatch.HomeProvider; + } + } } - long[] roamingConsortiums = roamingConsortium.getRoamingConsortiums(); - // Roaming Consortium OI information element matching. - if (roamingConsortiums != null && providerOIs != null) { - for (long sta_oi: roamingConsortiums) { - for (long ap_oi: providerOIs) { - if (sta_oi == ap_oi) { - return PasspointMatch.RoamingProvider; - } + // HomeOI matching + if (mConfig.getHomeSp().getMatchAllOis() != null) { + // Ensure that every HomeOI whose corresponding HomeOIRequired value is true shall match + // an OI in the Roaming Consortium advertised by the hotspot operator. + if (matchOis(mConfig.getHomeSp().getMatchAllOis(), (RoamingConsortiumElement) + anqpElements.get(ANQPElementType.ANQPRoamingConsortium), + roamingConsortiumFromAp, true)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "All HomeOI RCOI match: HomeProvider"); + } + return PasspointMatch.HomeProvider; + } + } else if (mConfig.getHomeSp().getMatchAnyOis() != null) { + // Ensure that any HomeOI whose corresponding HomeOIRequired value is false shall match + // an OI in the Roaming Consortium advertised by the hotspot operator. + if (matchOis(mConfig.getHomeSp().getMatchAnyOis(), (RoamingConsortiumElement) + anqpElements.get(ANQPElementType.ANQPRoamingConsortium), + roamingConsortiumFromAp, false)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "Any HomeOI RCOI match: HomeProvider"); } + return PasspointMatch.HomeProvider; } } + // Roaming Consortium OI matching. + if (matchOis(mConfig.getHomeSp().getRoamingConsortiumOis(), (RoamingConsortiumElement) + anqpElements.get(ANQPElementType.ANQPRoamingConsortium), + roamingConsortiumFromAp, false)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "ANQP RCOI match: RoamingProvider"); + } + return PasspointMatch.RoamingProvider; + } + if (mVerboseLoggingEnabled) { + Log.e(TAG, "No domain name or RCOI match"); + } return PasspointMatch.None; } @@ -768,4 +870,12 @@ public class PasspointProvider { simCredential.setEapType(eapType); return simCredential; } + + /** + * Enable verbose logging + * @param verbose more than 0 enables verbose logging + */ + public void enableVerboseLogging(int verbose) { + mVerboseLoggingEnabled = (verbose > 0) ? true : false; + } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java index 4d4ea4487..df9c332a3 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java @@ -33,7 +33,6 @@ import com.android.server.wifi.hotspot2.anqp.RoamingConsortiumElement; import com.android.server.wifi.hotspot2.anqp.ThreeGPPNetworkElement; import com.android.server.wifi.hotspot2.anqp.eap.AuthParam; import com.android.server.wifi.hotspot2.anqp.eap.EAPMethod; -import com.android.server.wifi.hotspot2.anqp.eap.InnerAuthEAP; import com.android.server.wifi.hotspot2.anqp.eap.NonEAPInnerAuth; import org.junit.Test; @@ -102,7 +101,7 @@ public class ANQPMatcherTest { */ @Test public void matchRoamingConsortiumWithNullElement() throws Exception { - assertFalse(ANQPMatcher.matchRoamingConsortium(null, new long[0])); + assertFalse(ANQPMatcher.matchRoamingConsortium(null, new long[0], false)); } /** @@ -116,23 +115,22 @@ public class ANQPMatcherTest { long oi = 0x1234L; RoamingConsortiumElement element = new RoamingConsortiumElement(Arrays.asList(new Long[] {oi})); - assertTrue(ANQPMatcher.matchRoamingConsortium(element, new long[] {oi})); + assertTrue(ANQPMatcher.matchRoamingConsortium(element, new long[] {oi}, false)); } /** - * Verify that an indeterminate match will be returned when matching a null NAI Realm + * Verify that no match will be returned when matching a null NAI Realm * ANQP element. * * @throws Exception */ @Test public void matchNAIRealmWithNullElement() throws Exception { - assertEquals(AuthMatch.INDETERMINATE, ANQPMatcher.matchNAIRealm(null, "test.com", - EAPConstants.EAP_TLS, new InnerAuthEAP(EAPConstants.EAP_TTLS))); + assertFalse(ANQPMatcher.matchNAIRealm(null, "test.com")); } /** - * Verify that an indeterminate match will be returned when matching a NAI Realm + * Verify that no match will be returned when matching a NAI Realm * ANQP element contained no NAI realm data. * * @throws Exception @@ -140,8 +138,7 @@ public class ANQPMatcherTest { @Test public void matchNAIRealmWithEmtpyRealmData() throws Exception { NAIRealmElement element = new NAIRealmElement(new ArrayList()); - assertEquals(AuthMatch.INDETERMINATE, ANQPMatcher.matchNAIRealm(element, "test.com", - EAPConstants.EAP_TLS, null)); + assertFalse(ANQPMatcher.matchNAIRealm(element, "test.com")); } /** @@ -157,38 +154,11 @@ public class ANQPMatcherTest { Arrays.asList(new String[] {realm}), new ArrayList()); NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.REALM, ANQPMatcher.matchNAIRealm(element, realm, - EAPConstants.EAP_TLS, null)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that method match will be returned when the specified EAP - * method only matches a eap method in the NAI Realm ANQP element if the element does not have - * auth params. - * - * @throws Exception - */ - @Test - public void matchNAIRealmWithMethodMatch() throws Exception { - // Test data. - String providerRealm = "test.com"; - String anqpRealm = "test2.com"; - NonEAPInnerAuth authParam = new NonEAPInnerAuth(NonEAPInnerAuth.AUTH_TYPE_MSCHAP); - int eapMethodID = EAPConstants.EAP_TLS; - - // Setup NAI Realm element that has EAP method and no auth params. - EAPMethod method = new EAPMethod(eapMethodID, new HashMap>()); - NAIRealmData realmData = new NAIRealmData( - Arrays.asList(new String[]{anqpRealm}), Arrays.asList(new EAPMethod[]{method})); - NAIRealmElement element = new NAIRealmElement( - Arrays.asList(new NAIRealmData[]{realmData})); - - assertEquals(AuthMatch.METHOD, - ANQPMatcher.matchNAIRealm(element, providerRealm, eapMethodID, authParam)); - } - - /** - * Verify that a realm and method match will be returned when the specified realm and EAP + * Verify that a realm match will be returned when the specified realm and EAP * method matches a realm in the NAI Realm ANQP element. * * @throws Exception @@ -206,12 +176,11 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.REALM | AuthMatch.METHOD, - ANQPMatcher.matchNAIRealm(element, realm, eapMethodID, null)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that an exact match will be returned when the specified realm, EAP + * Verify that a realm match will be returned when the specified realm, EAP * method, and the authentication parameter matches a realm with the associated EAP method and * authentication parameter in the NAI Realm ANQP element. * @@ -235,12 +204,11 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.EXACT, - ANQPMatcher.matchNAIRealm(element, realm, eapMethodID, authParam)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that a mismatch (AuthMatch.NONE) will be returned when the specified EAP method + * Verify that a realm match will be returned when the specified EAP method * doesn't match with the corresponding EAP method in the NAI Realm ANQP element. * * @throws Exception @@ -263,12 +231,11 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.NONE, - ANQPMatcher.matchNAIRealm(element, realm, EAPConstants.EAP_TLS, null)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that a mismatch (AuthMatch.NONE) will be returned when the specified authentication + * Verify that a realm match will be returned when the specified authentication * parameter doesn't match with the corresponding authentication parameter in the NAI Realm * ANQP element. * @@ -292,10 +259,8 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - // Mismatch in authentication type. - assertEquals(AuthMatch.NONE, - ANQPMatcher.matchNAIRealm(element, realm, EAPConstants.EAP_TTLS, - new NonEAPInnerAuth(NonEAPInnerAuth.AUTH_TYPE_PAP))); + // Mismatch in authentication type which we ignore. + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** @@ -458,4 +423,64 @@ public class ANQPMatcherTest { assertEquals(-1, ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(TEST_3GPP_FQDN, element)); } + + /** + * Verify that match is found when HomeOI contains some of the RCOIs advertised by an AP marked + * as not required. + * + * @throws Exception + */ + @Test + public void matchAnyHomeOi() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xdeadL, 0xf0cdL}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertTrue(ANQPMatcher.matchRoamingConsortium(element, providerOis, false)); + } + + /** + * Verify that no match is found when HomeOI does not contain any of the RCOIs advertised by an + * AP marked as not required. + * + * @throws Exception + */ + @Test + public void matchAnyHomeOiNegative() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0xabc2L, 0x1232L}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertFalse(ANQPMatcher.matchRoamingConsortium(element, providerOis, false)); + } + + /** + * Verify that match is found when HomeOI contains all of the RCOIs advertised by an AP marked + * as required. + * + * @throws Exception + */ + @Test + public void matchAllHomeOi() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xabcdL, 0xdeadL, 0xf0cdL}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertTrue(ANQPMatcher.matchRoamingConsortium(element, providerOis, true)); + } + + /** + * Verify that match is not found when HomeOI does not contain all of the RCOIs advertised by an + * AP marked as required. + * + * @throws Exception + */ + @Test + public void matchAllHomeOiNegative() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xdeadL, 0xf0cdL}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertFalse(ANQPMatcher.matchRoamingConsortium(element, providerOis, true)); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java index 31229c562..c35d67301 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java @@ -478,9 +478,10 @@ public class PasspointProviderTest { } /** - * Verify that there is no match when the provider's FQDN matches a domain name in the - * Domain Name ANQP element but the provider's credential doesn't match the authentication - * method provided in the NAI realm. + * Verify that Home provider is matched even when the provider's FQDN matches a domain name in + * the Domain Name ANQP element but the provider's credential doesn't match the authentication + * method provided in the NAI realm. This can happen when the infrastructure provider is not + * the identity provider, and authentication method matching is not required in the spec. * * @throws Exception */ @@ -509,7 +510,8 @@ public class PasspointProviderTest { anqpElementMap.put(ANQPElementType.ANQPNAIRealm, createNAIRealmElement(testRealm, EAPConstants.EAP_TLS, null)); - assertEquals(PasspointMatch.None, mProvider.match(anqpElementMap, mRoamingConsortium)); + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); } /** @@ -657,8 +659,8 @@ public class PasspointProviderTest { } /** - * Verify that there is no match when a roaming consortium OI matches an OI - * in the roaming consortium ANQP element and but NAI realm is not matched. + * Verify that there is Roaming provider match when a roaming consortium OI matches an OI + * in the roaming consortium ANQP element and regardless of NAI realm mismatch. * * @throws Exception */ @@ -689,7 +691,7 @@ public class PasspointProviderTest { anqpElementMap.put(ANQPElementType.ANQPNAIRealm, createNAIRealmElement(testRealm, EAPConstants.EAP_TLS, null)); - assertEquals(PasspointMatch.None, + assertEquals(PasspointMatch.RoamingProvider, mProvider.match(anqpElementMap, mRoamingConsortium)); } @@ -766,8 +768,14 @@ public class PasspointProviderTest { } /** - * Verify that there is no match when a roaming consortium OI matches an OI + * Verify that there is Roaming provider match when a roaming consortium OI matches an OI * in the roaming consortium information element, but NAI realm is not matched. + * This can happen in roaming federation where the infrastructure provider is not the + * identity provider. + * Page 133 in the Hotspot2.0 specification states: + * Per subclause 11.25.8 of [2], if the value of HomeOI matches an OI in the Roaming + * Consortium advertised by a hotspot operator, successful authentication with that hotspot + * is possible. * * @throws Exception */ @@ -799,7 +807,7 @@ public class PasspointProviderTest { anqpElementMap.put(ANQPElementType.ANQPNAIRealm, createNAIRealmElement(testRealm, EAPConstants.EAP_TLS, null)); - assertEquals(PasspointMatch.None, + assertEquals(PasspointMatch.RoamingProvider, mProvider.match(anqpElementMap, mRoamingConsortium)); } @@ -1354,4 +1362,167 @@ public class PasspointProviderTest { mProvider.setHasEverConnected(true); assertTrue(mProvider.getHasEverConnected()); } + + /** + * Verify that an expected WifiConfiguration will be returned for a Passpoint provider + * with a user credential. + * + * @throws Exception + */ + @Test + public void matchOtherPartnersDomainName() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setOtherHomePartners(new String [] {"test3.com"}); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + + // Setup Domain Name ANQP element to test2.com and test3.com + Map anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that matching Any HomeOI results in a Home Provider match + * + * @throws Exception + */ + @Test + public void matchAnyHomeOi() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAnyOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + Long[] anqpOis = new Long[] {0x1234L, 0xdeadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that non-matching Any HomeOI results in a None Provider match + * + * @throws Exception + */ + @Test + public void matchAnyHomeOiNegative() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAnyOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + Long[] anqpOis = new Long[] {0x12a4L, 0xceadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.None, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that matching All HomeOI results in a Home Provider match + * + * @throws Exception + */ + @Test + public void matchAllHomeOi() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAllOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + Long[] anqpOis = new Long[] {0x1234L, 0x2345L, 0xabcdL, 0xdeadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that non-matching All HomeOI results in a None Provider match + * + * @throws Exception + */ + @Test + public void matchAllHomeOiNegative() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAllOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + + // 0x1234 matches, but 0x2345 does not + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xdeadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.None, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } } -- cgit v1.2.3