diff options
7 files changed, 314 insertions, 31 deletions
diff --git a/service/java/com/android/server/wifi/ConfigurationMap.java b/service/java/com/android/server/wifi/ConfigurationMap.java index a5cd18f2a..443eef879 100644 --- a/service/java/com/android/server/wifi/ConfigurationMap.java +++ b/service/java/com/android/server/wifi/ConfigurationMap.java @@ -126,6 +126,30 @@ public class ConfigurationMap { ScanResultMatchInfo.fromScanResult(scanResult)); } + /** + * Retrieves a |WifiConfiguration| object with PSK key management, that is matching the provided + * |scanResult| SSID from the internal map. + * Used for upgrading WPA2-Personal networks to WPA3-Personal, when AP is in transition mode. + */ + public WifiConfiguration getPskNetworkByScanResultForCurrentUser(ScanResult scanResult) { + // Check if WPA2-Personal saved network is available + ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult); + matchInfo.networkType = WifiConfiguration.SECURITY_TYPE_PSK; + return mScanResultMatchInfoMapForCurrentUser.get(matchInfo); + } + + /** + * Retrieves a |WifiConfiguration| object with no security, that is matching the provided + * |scanResult| SSID from the internal map. + * Used for upgrading Open networks to OWE, when AP is in transition mode. + */ + public WifiConfiguration getOpenNetworkByScanResultForCurrentUser(ScanResult scanResult) { + // Check if Open saved network is available + ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult); + matchInfo.networkType = WifiConfiguration.SECURITY_TYPE_OPEN; + return mScanResultMatchInfoMapForCurrentUser.get(matchInfo); + } + public Collection<WifiConfiguration> valuesForAllUsers() { return mPerID.values(); } diff --git a/service/java/com/android/server/wifi/ScanResultMatchInfo.java b/service/java/com/android/server/wifi/ScanResultMatchInfo.java index b3d10cc38..1e15a3ecc 100644 --- a/service/java/com/android/server/wifi/ScanResultMatchInfo.java +++ b/service/java/com/android/server/wifi/ScanResultMatchInfo.java @@ -131,26 +131,8 @@ public class ScanResultMatchInfo { return false; } ScanResultMatchInfo other = (ScanResultMatchInfo) otherObj; - if (!Objects.equals(networkSsid, other.networkSsid)) { - return false; - } - boolean networkTypeEquals; - - // Detect <SSID, PSK+SAE> scan result and say it is equal to <SSID, PSK> configuration - if (other.pskSaeInTransitionMode && networkType == WifiConfiguration.SECURITY_TYPE_PSK - || (pskSaeInTransitionMode - && other.networkType == WifiConfiguration.SECURITY_TYPE_PSK)) { - networkTypeEquals = true; - } else if ((networkType == WifiConfiguration.SECURITY_TYPE_OPEN - && other.oweInTransitionMode) || (oweInTransitionMode - && other.networkType == WifiConfiguration.SECURITY_TYPE_OPEN)) { - // Special case we treat Enhanced Open and Open as equals. This is done to support the - // case where a saved network is Open but we found an OWE in transition network. - networkTypeEquals = true; - } else { - networkTypeEquals = networkType == other.networkType; - } - return networkTypeEquals; + return Objects.equals(networkSsid, other.networkSsid) + && networkType == other.networkType; } @Override diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 533155d0c..c027675ce 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -1117,6 +1117,7 @@ public class WifiConfigManager { if (randomizedMac != null) { newInternalConfig.setRandomizedMacAddress(randomizedMac); } + newInternalConfig.clonedNetworkConfigKey = externalConfig.clonedNetworkConfigKey; return newInternalConfig; } @@ -1401,6 +1402,27 @@ public class WifiConfigManager { Log.e(TAG, "Failed to remove network " + config.getPrintableSsid()); return false; } + + // Remove any cloned networks + if (config.clonedNetworkConfigKey != null) { + WifiConfiguration clonedConfig = getConfiguredNetwork(config.clonedNetworkConfigKey); + + if (clonedConfig != null) { + Log.d(TAG, "Removing cloned network " + clonedConfig.getPrintableSsid()); + if (!removeNetworkInternal(clonedConfig, uid)) { + Log.e(TAG, "Failed to remove network " + clonedConfig.getPrintableSsid()); + return false; + } + + if (clonedConfig.networkId == mLastSelectedNetworkId) { + clearLastSelectedNetwork(); + } + } else { + Log.w(TAG, "Could not find a cloned network with key " + + config.clonedNetworkConfigKey); + } + } + if (networkId == mLastSelectedNetworkId) { clearLastSelectedNetwork(); } @@ -2265,6 +2287,24 @@ public class WifiConfigManager { } catch (IllegalArgumentException e) { Log.e(TAG, "Failed to lookup network from config map", e); } + if (config == null) { + /** + * Special case for WPA3-Personal and OWE in transition mode. + * These networks will be treated as WPA3/OWE with a special flag that indicates + * transition mode enabled. If we have a matching WPA2/Open saved network, create a new + * upgraded WPA3/OWE network and use it to connect. + */ + ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult); + if (matchInfo.pskSaeInTransitionMode || matchInfo.oweInTransitionMode) { + if (handleTransitionNetwork(scanResult, matchInfo.pskSaeInTransitionMode)) { + try { + config = mConfiguredNetworks.getByScanResultForCurrentUser(scanResult); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to lookup network from config map", e); + } + } + } + } if (config != null) { if (mVerboseLoggingEnabled) { Log.v(TAG, "getSavedNetworkFromScanDetail Found " + config.configKey() @@ -2274,6 +2314,41 @@ public class WifiConfigManager { return config; } + private boolean handleTransitionNetwork(ScanResult scanResult, boolean isPskSae) { + WifiConfiguration config; + + if (isPskSae) { + config = mConfiguredNetworks.getPskNetworkByScanResultForCurrentUser(scanResult); + } else { + config = mConfiguredNetworks.getOpenNetworkByScanResultForCurrentUser(scanResult); + } + + if (config != null) { + // Create a new WPA3-Personal or OWE connection + WifiConfiguration newConfig = new WifiConfiguration(config); + newConfig.networkId = WifiConfiguration.INVALID_NETWORK_ID; + newConfig.clonedNetworkConfigKey = config.configKey(); + if (isPskSae) { + newConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); + } else { + newConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); + } + NetworkUpdateResult res = addOrUpdateNetwork(newConfig, config.creatorUid, + config.creatorName); + + if (!res.isSuccess()) { + Log.e(TAG, "Failed to add new configuration for " + newConfig.SSID); + return false; + } + config.clonedNetworkConfigKey = newConfig.configKey(); + addOrUpdateNetwork(config, config.creatorUid); + enableNetwork(res.netId, false, config.creatorUid); + return true; + } + + return false; + } + /** * Retrieves a configured network corresponding to the provided scan detail if one exists and * caches the provided |scanDetail| into the corresponding scan detail cache entry diff --git a/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java b/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java index 97141c496..b866b965b 100644 --- a/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java @@ -276,6 +276,7 @@ public class ConfigurationMapTest { verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createPskNetwork()); verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createWepNetwork()); verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createEapNetwork()); + verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createSaeNetwork()); } /** @@ -328,4 +329,54 @@ public class ConfigurationMapTest { mConfigs.clear(); assertNull(mConfigs.getByScanResultForCurrentUser(scanResult)); } + + /** + * Verifies that {@link ConfigurationMap#getPskNetworkByScanResultForCurrentUser(ScanResult)} + * can positively match a PSK network for transition mode AP. + */ + @Test + public void testFindPskNetworkFromSaeScanResult() { + final String wpa2Wpa3TransitionSsid = "\"WPA3-Transition\""; + WifiConfiguration saePskConfig = + WifiConfigurationTestUtil.createSaeNetwork(wpa2Wpa3TransitionSsid); + WifiConfiguration pskConfig = + WifiConfigurationTestUtil.createPskNetwork(wpa2Wpa3TransitionSsid); + mConfigs.put(saePskConfig); + mConfigs.put(pskConfig); + + ScanDetail scanDetail = WifiConfigurationTestUtil + .createScanDetailForWpa2Wpa3TransitionModeNetwork(saePskConfig, + "AA:BB:CC:DD:CC:BB", -40, 2402, 0, 1); + ScanResult scanResult = scanDetail.getScanResult(); + + WifiConfiguration retrievedConfig = + mConfigs.getPskNetworkByScanResultForCurrentUser(scanResult); + assertNotNull(retrievedConfig); + assertEquals(pskConfig.configKey(), retrievedConfig.configKey()); + } + + /** + * Verifies that {@link ConfigurationMap#getOpenNetworkByScanResultForCurrentUser(ScanResult)} + * can positively match a PSK network for transition mode AP. + */ + @Test + public void testFindOpenNetworkFromOweScanResult() { + final String oweTransitionSsid = "\"OWE-Transition\""; + WifiConfiguration oweOpenConfig = + WifiConfigurationTestUtil.createOweNetwork(oweTransitionSsid); + WifiConfiguration openConfig = + WifiConfigurationTestUtil.createOpenNetwork(oweTransitionSsid); + mConfigs.put(oweOpenConfig); + mConfigs.put(openConfig); + + ScanDetail scanDetail = WifiConfigurationTestUtil + .createScanDetailForOweTransitionModeNetwork(oweOpenConfig, + "AA:BB:CC:DD:CC:BB", -40, 2402, 0, 1); + ScanResult scanResult = scanDetail.getScanResult(); + + WifiConfiguration retrievedConfig = + mConfigs.getOpenNetworkByScanResultForCurrentUser(scanResult); + assertNotNull(retrievedConfig); + assertEquals(openConfig.configKey(), retrievedConfig.configKey()); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java b/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java index 2712ce077..b931e3f5b 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java @@ -92,7 +92,7 @@ public class ScanResultMatchInfoTest { @Test public void testEqualityRulesForTransitionMode() { WifiConfiguration wifiConfiguration = - WifiConfigurationTestUtil.createPskNetwork("\"Transition is Hard\""); + WifiConfigurationTestUtil.createSaeNetwork("\"Transition is Hard\""); ScanDetail scanDetail = createScanDetailForWpa2Wpa3TransitionModeNetwork(wifiConfiguration, "AA:BB:CC:DD:CC:BB"); diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index c4cbc6e50..c3b90d36c 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -185,6 +185,8 @@ public class WifiConfigManagerTest { return TEST_NO_PERM_NAME; } else if (uid == Process.WIFI_UID) { return TEST_WIFI_NAME; + } else if (uid == Process.SYSTEM_UID) { + return TEST_WIFI_NAME; } fail("Unexpected UID: " + uid); return ""; @@ -5349,4 +5351,133 @@ public class WifiConfigManagerTest { assertFalse(mWifiConfigManager.getConfiguredNetwork(networkId) .getNetworkSelectionStatus().isNetworkTemporaryDisabled()); } + + /** + * Verifies that when scanning a WPA3 in transition mode AP, and there is a matching WPA2 saved + * network, {@link WifiConfigManager#getConfiguredNetworkForScanDetailAndCache(ScanDetail)} + * clones a new WPA3 saved network that will be used to connect to it. + * + * The test also verifies that the new network is marked as cloned. + */ + @Test + public void testCloningPskNetworkForTransitionMode() { + final String wpa2Wpa3TransitionSsid = "\"WPA3-Transition\""; + WifiConfiguration saeNetwork = WifiConfigurationTestUtil + .createSaeNetwork(wpa2Wpa3TransitionSsid); + WifiConfiguration pskNetwork = WifiConfigurationTestUtil + .createPskNetwork(wpa2Wpa3TransitionSsid); + + // First add the WPA2 saved network. + verifyAddNetworkToWifiConfigManager(pskNetwork); + + // Now create a dummy scan detail for WPA3-Transition. + ScanDetail scanDetail = WifiConfigurationTestUtil + .createScanDetailForWpa2Wpa3TransitionModeNetwork(saeNetwork, + "AA:BB:CC:DD:CC:BB", -40, 2402, 0, 1); + + + WifiConfiguration retrievedNetwork = + mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail); + // Retrieve the network with password data for comparison. + retrievedNetwork = + mWifiConfigManager.getConfiguredNetworkWithPassword(retrievedNetwork.networkId); + + // Verify cloned network matches the expected WPA3 network + assertEquals(saeNetwork.SSID, retrievedNetwork.SSID); + assertEquals(saeNetwork.BSSID, retrievedNetwork.BSSID); + assertEquals(saeNetwork.preSharedKey, retrievedNetwork.preSharedKey); + assertEquals(saeNetwork.requirePMF, retrievedNetwork.requirePMF); + assertEquals(saeNetwork.allowedKeyManagement, retrievedNetwork.allowedKeyManagement); + assertNotNull(retrievedNetwork.clonedNetworkConfigKey); + assertEquals(retrievedNetwork.clonedNetworkConfigKey, pskNetwork.configKey()); + } + + /** + * Verifies that when scanning a WPA3 in transition mode AP, and there is a matching WPA2 saved + * network, {@link WifiConfigManager#getConfiguredNetworkForScanDetailAndCache(ScanDetail)} + * clones a new WPA3 saved network that will be used to connect to it. + * + * The test also verifies that the new network is marked as cloned. + */ + @Test + public void testCloningOweNetworkForTransitionMode() { + final String oweTransitionSsid = "\"OWE-Transition\""; + WifiConfiguration oweNetwork = WifiConfigurationTestUtil + .createOweNetwork(oweTransitionSsid); + WifiConfiguration openNetwork = WifiConfigurationTestUtil + .createOpenNetwork(oweTransitionSsid); + + // First add the Open saved network. + verifyAddNetworkToWifiConfigManager(openNetwork); + + // Now create a dummy scan detail for OWE-Transition. + ScanDetail scanDetail = WifiConfigurationTestUtil + .createScanDetailForOweTransitionModeNetwork(oweNetwork, + "AA:BB:CC:DD:CC:BB", -40, 2402, 0, 1); + + + WifiConfiguration retrievedNetwork = + mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail); + // Retrieve the network with password data for comparison. + retrievedNetwork = + mWifiConfigManager.getConfiguredNetworkWithPassword(retrievedNetwork.networkId); + + // Verify cloned network matches the expected OWE network + assertEquals(oweNetwork.SSID, retrievedNetwork.SSID); + assertEquals(oweNetwork.BSSID, retrievedNetwork.BSSID); + assertEquals(oweNetwork.preSharedKey, retrievedNetwork.preSharedKey); + assertEquals(oweNetwork.requirePMF, retrievedNetwork.requirePMF); + assertEquals(oweNetwork.allowedKeyManagement, retrievedNetwork.allowedKeyManagement); + assertNotNull(retrievedNetwork.clonedNetworkConfigKey); + assertEquals(retrievedNetwork.clonedNetworkConfigKey, openNetwork.configKey()); + } + + /** + * Verifies that when a cloned network is removed, its original pair is removed as well + * {@link WifiConfigManager#removeNetwork(int)} + */ + @Test + public void testRemoveClonedSaeNetwork() { + final String wpa2Wpa3TransitionSsid = "\"WPA3-Transition\""; + WifiConfiguration saeNetwork = WifiConfigurationTestUtil + .createSaeNetwork(wpa2Wpa3TransitionSsid); + WifiConfiguration pskNetwork = WifiConfigurationTestUtil + .createPskNetwork(wpa2Wpa3TransitionSsid); + + // First add the WPA2 saved network. + NetworkUpdateResult result = verifyAddNetworkToWifiConfigManager(pskNetwork); + verify(mWcmListener).onSavedNetworkAdded(result.netId); + reset(mWcmListener); + + // Now create a dummy scan detail for WPA3-Transition. + ScanDetail scanDetail = WifiConfigurationTestUtil + .createScanDetailForWpa2Wpa3TransitionModeNetwork(saeNetwork, + "AA:BB:CC:DD:CC:BB", -40, 2402, 0, 1); + + WifiConfiguration retrievedNetwork = + mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail); + // Retrieve the network with password data for comparison. + retrievedNetwork = + mWifiConfigManager.getConfiguredNetworkWithPassword(retrievedNetwork.networkId); + + // Verify cloned network matches the expected WPA3 network + assertEquals(saeNetwork.SSID, retrievedNetwork.SSID); + assertEquals(saeNetwork.BSSID, retrievedNetwork.BSSID); + assertEquals(saeNetwork.preSharedKey, retrievedNetwork.preSharedKey); + assertEquals(saeNetwork.requirePMF, retrievedNetwork.requirePMF); + assertEquals(saeNetwork.allowedKeyManagement, retrievedNetwork.allowedKeyManagement); + assertNotNull(retrievedNetwork.clonedNetworkConfigKey); + assertEquals(retrievedNetwork.clonedNetworkConfigKey, pskNetwork.configKey()); + + // Ensure that configured network list is not empty. + assertTrue(mWifiConfigManager.getConfiguredNetworks().size() == 2); + verify(mWcmListener).onSavedNetworkAdded(retrievedNetwork.networkId); + reset(mWcmListener); + + assertTrue(mWifiConfigManager.removeNetwork(retrievedNetwork.networkId, TEST_CREATOR_UID)); + + // Ensure that configured network list is empty now. + assertTrue(mWifiConfigManager.getConfiguredNetworks().isEmpty()); + verify(mWcmListener).onSavedNetworkRemoved(retrievedNetwork.networkId); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java index 056df7c37..826250497 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java @@ -248,8 +248,11 @@ public class WifiConfigurationTestUtil { } public static WifiConfiguration createOweNetwork(String ssid) { - return generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid, true, true, null, - null, SECURITY_OWE); + WifiConfiguration configuration = generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid, + true, true, null, null, SECURITY_OWE); + + configuration.requirePMF = true; + return configuration; } public static WifiConfiguration createOpenNetwork() { @@ -274,14 +277,7 @@ public class WifiConfigurationTestUtil { } public static WifiConfiguration createSaeNetwork() { - WifiConfiguration configuration = - generateWifiConfig(TEST_NETWORK_ID, TEST_UID, createNewSSID(), true, true, null, - null, SECURITY_SAE); - - // SAE password uses the same member. - configuration.preSharedKey = TEST_PSK; - configuration.requirePMF = true; - return configuration; + return createSaeNetwork(createNewSSID()); } public static WifiConfiguration createPskNetwork() { @@ -304,6 +300,10 @@ public class WifiConfigurationTestUtil { WifiConfiguration configuration = generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid, true, true, null, null, SECURITY_SAE); + + // SAE password uses the same member. + configuration.preSharedKey = TEST_PSK; + configuration.requirePMF = true; return configuration; } @@ -515,6 +515,15 @@ public class WifiConfigurationTestUtil { } /** + * Gets scan result capabilities for a WPA2/WPA3-Transition mode network configuration + */ + private static String + getScanResultCapsForOweTransitionNetwork(WifiConfiguration configuration) { + String caps = "[OWE_TRANSITION-CCMP]"; + return caps; + } + + /** * Creates a scan detail corresponding to the provided network and given BSSID, etc. */ public static ScanDetail createScanDetailForNetwork( @@ -537,6 +546,17 @@ public class WifiConfigurationTestUtil { return new ScanDetail(ssid, bssid, caps, level, frequency, tsf, seen); } + /** + * Creates a scan detail corresponding to the provided network and given BSSID, but sets + * the capabilities to OWE-Transition mode network. + */ + public static ScanDetail createScanDetailForOweTransitionModeNetwork( + WifiConfiguration configuration, String bssid, int level, int frequency, + long tsf, long seen) { + String caps = getScanResultCapsForOweTransitionNetwork(configuration); + WifiSsid ssid = WifiSsid.createFromAsciiEncoded(configuration.getPrintableSsid()); + return new ScanDetail(ssid, bssid, caps, level, frequency, tsf, seen); + } /** * Asserts that the 2 WifiConfigurations are equal in the elements saved for both backup/restore |