summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:20:30 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:20:30 +0000
commit0911ae9d2c40de055de179335185dedc0b314bb3 (patch)
tree3ba01144cff18cb394df313f542a1c00095c0891
parentf982ce2eeffcf234c0fb24ad8ac6f1ac3f750e54 (diff)
parent7fd98cf74b6b02b77f04d0a8cb93bb8f39ffa6a7 (diff)
downloadwifi-android10-mainline-networking-release.tar.gz
Snap for 6001391 from 7fd98cf74b6b02b77f04d0a8cb93bb8f39ffa6a7 to qt-aml-networking-releaseandroid-mainline-10.0.0_r6android10-mainline-networking-release
Change-Id: I5258c9a0647fbb4c7ff3b8966e3769dd7bdb0a15
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java21
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java108
-rw-r--r--service/java/com/android/server/wifi/WifiConfigurationUtil.java102
-rw-r--r--service/java/com/android/server/wifi/rtt/RttNative.java15
-rw-r--r--service/java/com/android/server/wifi/util/TelephonyUtil.java40
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java64
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java18
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java30
-rw-r--r--tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java24
9 files changed, 378 insertions, 44 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 7e7f651de..119d6d0e8 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -4473,14 +4473,25 @@ public class ClientModeImpl extends StateMachine {
config.enterpriseConfig.getEapMethod())) {
String anonymousIdentity =
mWifiNative.getEapAnonymousIdentity(mInterfaceName);
- if (mVerboseLoggingEnabled) {
- log("EAP Pseudonym: " + anonymousIdentity);
- }
- if (!TelephonyUtil.isAnonymousAtRealmIdentity(anonymousIdentity)) {
+ if (!TextUtils.isEmpty(anonymousIdentity)
+ && !TelephonyUtil
+ .isAnonymousAtRealmIdentity(anonymousIdentity)) {
+ String decoratedPseudonym = TelephonyUtil
+ .decoratePseudonymWith3GppRealm(getTelephonyManager(),
+ anonymousIdentity);
+ if (decoratedPseudonym != null) {
+ anonymousIdentity = decoratedPseudonym;
+ }
+ if (mVerboseLoggingEnabled) {
+ log("EAP Pseudonym: " + anonymousIdentity);
+ }
// Save the pseudonym only if it is a real one
config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
- mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
+ } else {
+ // Clear any stored pseudonyms
+ config.enterpriseConfig.setAnonymousIdentity(null);
}
+ mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
}
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mObtainingIpState);
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 683ace4c8..d1734d445 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -76,6 +76,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.crypto.Mac;
+
/**
* This class provides the APIs to manage configured Wi-Fi networks.
* It deals with the following:
@@ -228,6 +230,9 @@ public class WifiConfigManager {
private static final int WIFI_PNO_FREQUENCY_CULLING_ENABLED_DEFAULT = 1; // 0 = disabled
private static final int WIFI_PNO_RECENCY_SORTING_ENABLED_DEFAULT = 1; // 0 = disabled:
+ private static final MacAddress DEFAULT_MAC_ADDRESS =
+ MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
+
/**
* Expiration timeout for deleted ephemeral ssids. (1 day)
*/
@@ -272,6 +277,7 @@ public class WifiConfigManager {
private final WifiPermissionsWrapper mWifiPermissionsWrapper;
private final WifiInjector mWifiInjector;
private boolean mConnectedMacRandomzationSupported;
+ private final Mac mMac;
/**
* Local log used for debugging any WifiConfigManager issues.
@@ -446,6 +452,11 @@ public class WifiConfigManager {
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Unable to resolve SystemUI's UID.");
}
+ mMac = WifiConfigurationUtil.obtainMacRandHashFunction(Process.WIFI_UID);
+ if (mMac == null) {
+ Log.wtf(TAG, "Failed to obtain secret for MAC randomization."
+ + " All randomized MAC addresses are lost!");
+ }
}
/**
@@ -464,6 +475,59 @@ public class WifiConfigManager {
return sb.toString();
}
+ @VisibleForTesting
+ protected int getRandomizedMacAddressMappingSize() {
+ return mRandomizedMacAddressMapping.size();
+ }
+
+ /**
+ * The persistent randomized MAC address is locally generated for each SSID and does not
+ * change until factory reset of the device. In the initial Q release the per-SSID randomized
+ * MAC is saved on the device, but in an update the storing of randomized MAC is removed.
+ * Instead, the randomized MAC is calculated directly from the SSID and a on device secret.
+ * For backward compatibility, this method first checks the device storage for saved
+ * randomized MAC. If it is not found or the saved MAC is invalid then it will calculate the
+ * randomized MAC directly.
+ *
+ * In the future as devices launched on Q no longer get supported, this method should get
+ * simplified to return the calculated MAC address directly.
+ * @param config the WifiConfiguration to obtain MAC address for.
+ * @return persistent MAC address for this WifiConfiguration
+ */
+ private MacAddress getPersistentMacAddress(WifiConfiguration config) {
+ // mRandomizedMacAddressMapping had been the location to save randomized MAC addresses.
+ String persistentMacString = mRandomizedMacAddressMapping.get(
+ config.getSsidAndSecurityTypeString());
+ // Use the MAC address stored in the storage if it exists and is valid. Otherwise
+ // use the MAC address calculated from a hash function as the persistent MAC.
+ if (persistentMacString != null) {
+ try {
+ return MacAddress.fromString(persistentMacString);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Error creating randomized MAC address from stored value.");
+ mRandomizedMacAddressMapping.remove(config.getSsidAndSecurityTypeString());
+ }
+ }
+ return WifiConfigurationUtil.calculatePersistentMacForConfiguration(config, mMac);
+ }
+
+ /**
+ * Obtain the persistent MAC address by first reading from an internal database. If non exists
+ * then calculate the persistent MAC using HMAC-SHA256.
+ * Finally set the randomized MAC of the configuration to the randomized MAC obtained.
+ * @param config the WifiConfiguration to make the update
+ * @return the persistent MacAddress or null if the operation is unsuccessful
+ */
+ private MacAddress setRandomizedMacToPersistentMac(WifiConfiguration config) {
+ MacAddress persistentMac = getPersistentMacAddress(config);
+ if (persistentMac == null || persistentMac.equals(config.getRandomizedMacAddress())) {
+ return persistentMac;
+ }
+ WifiConfiguration internalConfig = getInternalConfiguredNetwork(config.networkId);
+ internalConfig.setRandomizedMacAddress(persistentMac);
+ return persistentMac;
+ }
+
/**
* Enable/disable verbose logging in WifiConfigManager & its helper classes.
*/
@@ -520,8 +584,7 @@ public class WifiConfigManager {
* @param configuration WifiConfiguration to hide the MAC address
*/
private void maskRandomizedMacAddressInWifiConfiguration(WifiConfiguration configuration) {
- MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
- configuration.setRandomizedMacAddress(defaultMac);
+ configuration.setRandomizedMacAddress(DEFAULT_MAC_ADDRESS);
}
/**
@@ -1050,34 +1113,11 @@ public class WifiConfigManager {
packageName != null ? packageName : mContext.getPackageManager().getNameForUid(uid);
newInternalConfig.creationTime = newInternalConfig.updateTime =
createDebugTimeStampString(mClock.getWallClockMillis());
- updateRandomizedMacAddress(newInternalConfig);
-
- return newInternalConfig;
- }
-
- /**
- * Sets the randomized address for the given configuration from stored map if it exist.
- * Otherwise generates a new randomized address and save to the stored map.
- * @param config
- */
- private void updateRandomizedMacAddress(WifiConfiguration config) {
- // Update randomized MAC address according to stored map
- final String key = config.getSsidAndSecurityTypeString();
- // If the key is not found in the current store, then it means this network has never been
- // seen before. So add it to store.
- if (!mRandomizedMacAddressMapping.containsKey(key)) {
- mRandomizedMacAddressMapping.put(key,
- config.getOrCreateRandomizedMacAddress().toString());
- } else { // Otherwise read from the store and set the WifiConfiguration
- try {
- config.setRandomizedMacAddress(
- MacAddress.fromString(mRandomizedMacAddressMapping.get(key)));
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Error creating randomized MAC address from stored value.");
- mRandomizedMacAddressMapping.put(key,
- config.getOrCreateRandomizedMacAddress().toString());
- }
+ MacAddress randomizedMac = getPersistentMacAddress(newInternalConfig);
+ if (randomizedMac != null) {
+ newInternalConfig.setRandomizedMacAddress(randomizedMac);
}
+ return newInternalConfig;
}
/**
@@ -3026,12 +3066,16 @@ public class WifiConfigManager {
}
/**
- * Generate randomized MAC addresses for configured networks and persist mapping to storage.
+ * Assign randomized MAC addresses for configured networks.
+ * This is needed to generate persistent randomized MAC address for existing networks when
+ * a device updates to Q+ for the first time since we are not calling addOrUpdateNetwork when
+ * we load configuration at boot.
*/
private void generateRandomizedMacAddresses() {
for (WifiConfiguration config : getInternalConfiguredNetworks()) {
- mRandomizedMacAddressMapping.put(config.getSsidAndSecurityTypeString(),
- config.getOrCreateRandomizedMacAddress().toString());
+ if (DEFAULT_MAC_ADDRESS.equals(config.getRandomizedMacAddress())) {
+ setRandomizedMacToPersistentMac(config);
+ }
}
}
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 59d3eb3f4..b8992a011 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -28,6 +28,9 @@ import android.net.wifi.WifiNetworkSpecifier;
import android.net.wifi.WifiScanner;
import android.os.PatternMatcher;
import android.os.UserHandle;
+import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -36,7 +39,17 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.util.NativeUtil;
import com.android.server.wifi.util.TelephonyUtil;
+import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.ProviderException;
+import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.BitSet;
@@ -44,6 +57,10 @@ import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+
/**
* WifiConfiguration utility for any {@link android.net.wifi.WifiConfiguration} related operations.
* Currently contains:
@@ -72,6 +89,10 @@ public class WifiConfigurationUtil {
new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ private static final String MAC_RANDOMIZATION_ALIAS = "MacRandSecret";
+ private static final long MAC_ADDRESS_VALID_LONG_MASK = (1L << 48) - 1;
+ private static final long MAC_ADDRESS_LOCALLY_ASSIGNED_MASK = 1L << 41;
+ private static final long MAC_ADDRESS_MULTICAST_MASK = 1L << 40;
/**
* Check whether a network configuration is visible to a user or any of its managed profiles.
@@ -227,6 +248,87 @@ public class WifiConfigurationUtil {
}
/**
+ * Computes the persistent randomized MAC of the given configuration using the given
+ * hash function.
+ * @param config the WifiConfiguration to compute MAC address for
+ * @param hashFunction the hash function that will perform the MAC address computation.
+ * @return The persistent randomized MAC address or null if inputs are invalid.
+ */
+ public static MacAddress calculatePersistentMacForConfiguration(WifiConfiguration config,
+ Mac hashFunction) {
+ if (config == null || hashFunction == null) {
+ return null;
+ }
+ byte[] hashedBytes = hashFunction.doFinal(
+ config.getSsidAndSecurityTypeString().getBytes(StandardCharsets.UTF_8));
+ ByteBuffer bf = ByteBuffer.wrap(hashedBytes);
+ long longFromSsid = bf.getLong();
+ /**
+ * Masks the generated long so that it represents a valid randomized MAC address.
+ * Specifically, this sets the locally assigned bit to 1, multicast bit to 0
+ */
+ longFromSsid &= MAC_ADDRESS_VALID_LONG_MASK;
+ longFromSsid |= MAC_ADDRESS_LOCALLY_ASSIGNED_MASK;
+ longFromSsid &= ~MAC_ADDRESS_MULTICAST_MASK;
+ bf.clear();
+ bf.putLong(0, longFromSsid);
+
+ // MacAddress.fromBytes requires input of length 6, which is obtained from the
+ // last 6 bytes from the generated long.
+ MacAddress macAddress = MacAddress.fromBytes(Arrays.copyOfRange(bf.array(), 2, 8));
+ return macAddress;
+ }
+
+ /**
+ * Retrieves a Hash function that could be used to calculate the persistent randomized MAC
+ * for a WifiConfiguration.
+ * @param uid the UID of the KeyStore to get the secret of the hash function from.
+ */
+ public static Mac obtainMacRandHashFunction(int uid) {
+ try {
+ KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(uid);
+ // tries to retrieve the secret, and generate a new one if it's unavailable.
+ Key key = keyStore.getKey(MAC_RANDOMIZATION_ALIAS, null);
+ if (key == null) {
+ key = generateAndPersistNewMacRandomizationSecret(uid);
+ }
+ if (key == null) {
+ Log.e(TAG, "Failed to generate secret for " + MAC_RANDOMIZATION_ALIAS);
+ return null;
+ }
+ Mac result = Mac.getInstance("HmacSHA256");
+ result.init(key);
+ return result;
+ } catch (KeyStoreException | NoSuchAlgorithmException | InvalidKeyException
+ | UnrecoverableKeyException | NoSuchProviderException e) {
+ Log.e(TAG, "Failure in obtainMacRandHashFunction", e);
+ return null;
+ }
+ }
+
+ /**
+ * Generates and returns a secret key to use for Mac randomization.
+ * Will also persist the generated secret inside KeyStore, accessible in the
+ * future with KeyGenerator#getKey.
+ */
+ private static SecretKey generateAndPersistNewMacRandomizationSecret(int uid) {
+ try {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore");
+ keyGenerator.init(
+ new KeyGenParameterSpec.Builder(MAC_RANDOMIZATION_ALIAS,
+ KeyProperties.PURPOSE_SIGN)
+ .setUid(uid)
+ .build());
+ return keyGenerator.generateKey();
+ } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
+ | NoSuchProviderException | ProviderException e) {
+ Log.e(TAG, "Failure in generateMacRandomizationSecret", e);
+ return null;
+ }
+ }
+
+ /**
* Compare existing and new WifiEnterpriseConfig objects after a network update and return if
* credential parameters have changed or not.
*
diff --git a/service/java/com/android/server/wifi/rtt/RttNative.java b/service/java/com/android/server/wifi/rtt/RttNative.java
index eaf947062..ffbf5bef9 100644
--- a/service/java/com/android/server/wifi/rtt/RttNative.java
+++ b/service/java/com/android/server/wifi/rtt/RttNative.java
@@ -311,6 +311,7 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub {
config.channel.centerFreq1 = responder.centerFreq1;
config.bw = halRttChannelBandwidthFromResponderChannelWidth(responder.channelWidth);
config.preamble = halRttPreambleFromResponderPreamble(responder.preamble);
+ validateBwAndPreambleCombination(config.bw, config.preamble);
if (config.peer == RttPeerType.NAN) {
config.mustRequestLci = false;
@@ -349,6 +350,20 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub {
return rttConfigs;
}
+ private static void validateBwAndPreambleCombination(int bw, int preamble) {
+ if (bw <= RttBw.BW_20MHZ) {
+ return;
+ }
+ if (bw == RttBw.BW_40MHZ && preamble >= RttPreamble.HT) {
+ return;
+ }
+ if (bw >= RttBw.BW_80MHZ && preamble >= RttPreamble.VHT) {
+ return;
+ }
+ throw new IllegalArgumentException(
+ "bw and preamble combination is invalid, bw: " + bw + " preamble: " + preamble);
+ }
+
private static int halRttPeerTypeFromResponderType(int responderType) {
switch (responderType) {
case ResponderConfig.RESPONDER_AP:
diff --git a/service/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java
index 4af40ddf2..3154df978 100644
--- a/service/java/com/android/server/wifi/util/TelephonyUtil.java
+++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java
@@ -22,6 +22,7 @@ import android.net.wifi.WifiEnterpriseConfig;
import android.telephony.ImsiEncryptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
@@ -730,4 +731,43 @@ public class TelephonyUtil {
public static boolean isSimPresent(@Nonnull SubscriptionManager sm) {
return sm.getActiveSubscriptionIdList().length > 0;
}
+
+ /**
+ * Decorates a pseudonym with the NAI realm, in case it wasn't provided by the server
+ *
+ * @param tm TelephonyManager instance
+ * @param pseudonym The pseudonym (temporary identity) provided by the server
+ * @return pseudonym@realm which is based on current MCC/MNC, {@code null} if SIM is
+ * not ready or absent.
+ */
+ public static String decoratePseudonymWith3GppRealm(@NonNull TelephonyManager tm,
+ String pseudonym) {
+ if (tm == null || TextUtils.isEmpty(pseudonym)) {
+ return null;
+ }
+ if (pseudonym.contains("@")) {
+ // Pseudonym is already decorated
+ return pseudonym;
+ }
+ TelephonyManager defaultDataTm = tm.createForSubscriptionId(
+ SubscriptionManager.getDefaultDataSubscriptionId());
+ if (defaultDataTm.getSimState() != TelephonyManager.SIM_STATE_READY) {
+ return null;
+ }
+ String mccMnc = defaultDataTm.getSimOperator();
+ if (mccMnc == null || mccMnc.isEmpty()) {
+ return null;
+ }
+
+ // Extract mcc & mnc from mccMnc
+ String mcc = mccMnc.substring(0, 3);
+ String mnc = mccMnc.substring(3);
+
+ if (mnc.length() == 2) {
+ mnc = "0" + mnc;
+ }
+
+ String realm = String.format(THREE_GPP_NAI_REALM_FORMAT, mnc, mcc);
+ return String.format("%s@%s", pseudonym, realm);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index c3e31131d..9eb88b637 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -1047,6 +1047,9 @@ public class ClientModeImplTest {
when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
+ // Initial value should be "not set"
+ assertEquals("", mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
+
triggerConnect();
// CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
@@ -1066,15 +1069,15 @@ public class ClientModeImplTest {
mLooper.dispatchAll();
verify(mWifiNative).getEapAnonymousIdentity(any());
- // check that the anonymous identity remains anonymous@<realm> for subsequent connections.
- assertEquals(expectedAnonymousIdentity,
- mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
- // verify that WifiConfigManager#addOrUpdateNetwork() was never called if there is no
- // real pseudonym to be stored. i.e. Encrypted IMSI will be always used
+
+ // Post connection value should remain "not set"
+ assertEquals("", mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
+ // verify that WifiConfigManager#addOrUpdateNetwork() was called to clear any previously
+ // stored pseudonym. i.e. to enable Encrypted IMSI for subsequent connections.
// Note: This test will fail if future logic will have additional conditions that would
// trigger "add or update network" operation. The test needs to be updated to account for
// this change.
- verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt());
+ verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
}
/**
@@ -1127,6 +1130,55 @@ public class ClientModeImplTest {
}
/**
+ * Tests anonymous identity is set again whenever a connection is established for the carrier
+ * that supports encrypted IMSI and anonymous identity but real but not decorated pseudonym was
+ * provided for subsequent connections.
+ */
+ @Test
+ public void testSetAnonymousIdentityWhenConnectionIsEstablishedWithNonDecoratedPseudonym()
+ throws Exception {
+ mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
+ WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
+ when(mDataTelephonyManager.getSimOperator()).thenReturn("123456");
+ when(mDataTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+ mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
+
+ String realm = "wlan.mnc456.mcc123.3gppnetwork.org";
+ String expectedAnonymousIdentity = "anonymous";
+ String pseudonym = "83bcca9384fca";
+
+ when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
+
+ triggerConnect();
+
+ // CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
+ assertEquals(expectedAnonymousIdentity + "@" + realm,
+ mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
+
+ when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
+ .thenReturn(mScanDetailCache);
+ when(mScanDetailCache.getScanDetail(sBSSID)).thenReturn(
+ getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq));
+ when(mScanDetailCache.getScanResult(sBSSID)).thenReturn(
+ getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq).getScanResult());
+ when(mWifiNative.getEapAnonymousIdentity(anyString()))
+ .thenReturn(pseudonym);
+
+ mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
+ mLooper.dispatchAll();
+
+ verify(mWifiNative).getEapAnonymousIdentity(any());
+ assertEquals(pseudonym + "@" + realm,
+ mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
+ // Verify that WifiConfigManager#addOrUpdateNetwork() was called if there we received a
+ // real pseudonym to be stored. i.e. Encrypted IMSI will be used once, followed by
+ // pseudonym usage in all subsequent connections.
+ // Note: This test will fail if future logic will have additional conditions that would
+ // trigger "add or update network" operation. The test needs to be updated to account for
+ // this change.
+ verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
+ }
+ /**
* Tests the Passpoint information is set in WifiInfo for Passpoint AP connection.
*/
@Test
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 686b2098d..0badc6fbd 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -63,6 +63,7 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -111,6 +112,8 @@ public class WifiConfigManagerTest {
private static final int TEST_FREQUENCY_1 = 2412;
private static final int TEST_FREQUENCY_2 = 5180;
private static final int TEST_FREQUENCY_3 = 5240;
+ private static final MacAddress TEST_RANDOMIZED_MAC =
+ MacAddress.fromString("d2:11:19:34:a5:20");
@Mock private Context mContext;
@Mock private Clock mClock;
@@ -228,9 +231,13 @@ public class WifiConfigManagerTest {
// static mocking
mSession = ExtendedMockito.mockitoSession()
.mockStatic(WifiConfigStore.class, withSettings().lenient())
+ .spyStatic(WifiConfigurationUtil.class)
+ .strictness(Strictness.LENIENT)
.startMocking();
when(WifiConfigStore.createUserFiles(anyInt())).thenReturn(mock(List.class));
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mDataTelephonyManager);
+ when(WifiConfigurationUtil.calculatePersistentMacForConfiguration(any(), any()))
+ .thenReturn(TEST_RANDOMIZED_MAC);
}
/**
@@ -239,7 +246,9 @@ public class WifiConfigManagerTest {
@After
public void cleanup() {
validateMockitoUsage();
- mSession.finishMocking();
+ if (mSession != null) {
+ mSession.finishMocking();
+ }
}
/**
@@ -368,6 +377,7 @@ public class WifiConfigManagerTest {
*/
@Test
public void testAddingNetworkWithMatchingMacAddressOverridesField() {
+ int prevMappingSize = mWifiConfigManager.getRandomizedMacAddressMappingSize();
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
Map<String, String> randomizedMacAddressMapping = new HashMap<>();
final String randMac = "12:23:34:45:56:67";
@@ -382,6 +392,9 @@ public class WifiConfigManagerTest {
List<WifiConfiguration> retrievedNetworks =
mWifiConfigManager.getConfiguredNetworksWithPasswords();
assertEquals(randMac, retrievedNetworks.get(0).getRandomizedMacAddress().toString());
+ // Verify that for networks that we already have randomizedMacAddressMapping saved
+ // we are still correctly writing into the WifiConfigStore.
+ assertEquals(prevMappingSize + 1, mWifiConfigManager.getRandomizedMacAddressMappingSize());
}
/**
@@ -391,6 +404,7 @@ public class WifiConfigManagerTest {
*/
@Test
public void testRandomizedMacAddressIsPersistedOverForgetNetwork() {
+ int prevMappingSize = mWifiConfigManager.getRandomizedMacAddressMappingSize();
// Create and add an open network
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
verifyAddNetworkToWifiConfigManager(openNetwork);
@@ -410,6 +424,8 @@ public class WifiConfigManagerTest {
verifyAddNetworkToWifiConfigManager(openNetwork);
retrievedNetworks = mWifiConfigManager.getConfiguredNetworksWithPasswords();
assertEquals(randMac, retrievedNetworks.get(0).getRandomizedMacAddress().toString());
+ // Verify that we are no longer persisting the randomized MAC address with WifiConfigStore.
+ assertEquals(prevMappingSize, mWifiConfigManager.getRandomizedMacAddressMappingSize());
}
/**
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index c1640ce91..7173dae5b 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -25,6 +25,7 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiNetworkSpecifier;
import android.net.wifi.WifiScanner;
+import android.os.Binder;
import android.os.PatternMatcher;
import android.os.UserHandle;
import android.util.Pair;
@@ -39,6 +40,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import javax.crypto.Mac;
+
/**
* Unit tests for {@link com.android.server.wifi.WifiConfigurationUtil}.
*/
@@ -961,6 +964,33 @@ public class WifiConfigurationUtilTest {
existingConfig, newConfig));
}
+ /**
+ * Verifies that calculatePersistentMacForConfiguration produces persistent, locally generated
+ * MAC addresses that are valid for MAC randomization.
+ */
+ @Test
+ public void testCalculatePersistentMacForConfiguration() {
+ // verify null inputs
+ assertNull(WifiConfigurationUtil.calculatePersistentMacForConfiguration(null, null));
+
+ // test multiple times since there is some randomness involved with hashing
+ int uid = Binder.getCallingUid();
+ for (int i = 0; i < 10; i++) {
+ // Verify that a the MAC address calculated is valid
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+ Mac hashFunction = WifiConfigurationUtil.obtainMacRandHashFunction(uid);
+ MacAddress macAddress = WifiConfigurationUtil.calculatePersistentMacForConfiguration(
+ config, hashFunction);
+ assertTrue(WifiConfiguration.isValidMacAddressForRandomization(macAddress));
+
+ // Verify that the secret used to generate MAC address is persistent
+ Mac hashFunction2 = WifiConfigurationUtil.obtainMacRandHashFunction(uid);
+ MacAddress macAddress2 = WifiConfigurationUtil.calculatePersistentMacForConfiguration(
+ config, hashFunction2);
+ assertEquals(macAddress, macAddress2);
+ }
+ }
+
private static class EnterpriseConfig {
public String eap;
public String phase2;
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
index d2f22da6a..bd0ad321d 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
@@ -18,6 +18,7 @@
package com.android.server.wifi.rtt;
import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -42,6 +43,7 @@ import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
import android.net.MacAddress;
import android.net.wifi.rtt.RangingRequest;
+import android.net.wifi.rtt.ResponderConfig;
import androidx.test.filters.SmallTest;
@@ -465,6 +467,28 @@ public class RttNativeTest {
}
}
+ /**
+ * Validation ranging with invalid bw and preamble combination will be ignored.
+ */
+ @Test
+ public void testRangingWithInvalidParameterCombination() throws Exception {
+ int cmdId = 88;
+ RangingRequest request = new RangingRequest.Builder().build();
+ ResponderConfig invalidConfig = new ResponderConfig(
+ MacAddress.fromString("08:09:08:07:06:88"), ResponderConfig.RESPONDER_AP, true,
+ ResponderConfig.CHANNEL_WIDTH_80MHZ, 0, 0, 0, ResponderConfig.PREAMBLE_HT);
+ ResponderConfig config = new ResponderConfig(MacAddress.fromString("08:09:08:07:06:89"),
+ ResponderConfig.RESPONDER_AP, true,
+ ResponderConfig.CHANNEL_WIDTH_80MHZ, 0, 0, 0, ResponderConfig.PREAMBLE_VHT);
+
+ // Add a ResponderConfig with invalid parameter, should be ignored.
+ request.mRttPeers.add(invalidConfig);
+ request.mRttPeers.add(config);
+ mDut.rangeRequest(cmdId, request, true);
+ verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
+ assertEquals(request.mRttPeers.size() - 1, mRttConfigCaptor.getValue().size());
+ }
+
// Utilities
/**