diff options
6 files changed, 62 insertions, 39 deletions
diff --git a/service/java/com/android/server/wifi/MacAddressUtil.java b/service/java/com/android/server/wifi/MacAddressUtil.java index effa931a5..a29c3fce9 100644 --- a/service/java/com/android/server/wifi/MacAddressUtil.java +++ b/service/java/com/android/server/wifi/MacAddressUtil.java @@ -17,7 +17,6 @@ package com.android.server.wifi; import android.net.MacAddress; -import android.net.wifi.WifiConfiguration; import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; @@ -46,24 +45,22 @@ import javax.crypto.SecretKey; public class MacAddressUtil { private static final String TAG = "MacAddressUtil"; private static final String MAC_RANDOMIZATION_ALIAS = "MacRandSecret"; + private static final String MAC_RANDOMIZATION_SAP_ALIAS = "MacRandSapSecret"; 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; /** - * Computes the persistent randomized MAC of the given configuration using the given - * hash function. - * @param config the WifiConfiguration to compute MAC address for + * Computes the persistent randomized MAC using the given key and hash function. + * @param key the key 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 MacAddress calculatePersistentMacForConfiguration(WifiConfiguration config, - Mac hashFunction) { - if (config == null || hashFunction == null) { + public MacAddress calculatePersistentMac(String key, Mac hashFunction) { + if (key == null || hashFunction == null) { return null; } - byte[] hashedBytes = hashFunction.doFinal( - config.getSsidAndSecurityTypeString().getBytes(StandardCharsets.UTF_8)); + byte[] hashedBytes = hashFunction.doFinal(key.getBytes(StandardCharsets.UTF_8)); ByteBuffer bf = ByteBuffer.wrap(hashedBytes); long longFromSsid = bf.getLong(); /** @@ -82,21 +79,16 @@ public class MacAddressUtil { 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 Mac obtainMacRandHashFunction(int uid) { + private Mac obtainMacRandHashFunctionInternal(int uid, String alias) { 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); + Key key = keyStore.getKey(alias, null); if (key == null) { - key = generateAndPersistNewMacRandomizationSecret(uid); + key = generateAndPersistNewMacRandomizationSecret(uid, alias); } if (key == null) { - Log.e(TAG, "Failed to generate secret for " + MAC_RANDOMIZATION_ALIAS); + Log.e(TAG, "Failed to generate secret for " + alias); return null; } Mac result = Mac.getInstance("HmacSHA256"); @@ -110,16 +102,34 @@ public class MacAddressUtil { } /** + * Retrieves a Hash function that could be used to calculate the persistent randomized MAC + * for a WifiConfiguration for client mode. + * @param uid the UID of the KeyStore to get the secret of the hash function from. + */ + public Mac obtainMacRandHashFunction(int uid) { + return obtainMacRandHashFunctionInternal(uid, MAC_RANDOMIZATION_ALIAS); + } + + /** + * Retrieves a Hash function that could be used to calculate the persistent randomized MAC + * for a WifiConfiguration for Soft AP. + * @param uid the UID of the KeyStore to get the secret of the hash function from. + */ + public Mac obtainMacRandHashFunctionForSap(int uid) { + return obtainMacRandHashFunctionInternal(uid, MAC_RANDOMIZATION_SAP_ALIAS); + } + + /** * 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 SecretKey generateAndPersistNewMacRandomizationSecret(int uid) { + private SecretKey generateAndPersistNewMacRandomizationSecret(int uid, String alias) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore"); keyGenerator.init( - new KeyGenParameterSpec.Builder(MAC_RANDOMIZATION_ALIAS, + new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_SIGN) .setUid(uid) .build()); diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java index c7499af3c..7cb7a4cef 100644 --- a/service/java/com/android/server/wifi/WifiApConfigStore.java +++ b/service/java/com/android/server/wifi/WifiApConfigStore.java @@ -30,6 +30,7 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; import android.os.Environment; import android.os.Handler; +import android.os.Process; import android.text.TextUtils; import android.util.Log; @@ -50,6 +51,7 @@ import java.util.ArrayList; import java.util.Random; import javax.annotation.Nullable; +import javax.crypto.Mac; /** * Provides API for reading/writing soft access point configuration. @@ -92,6 +94,8 @@ public class WifiApConfigStore { private final String mApConfigFile; private final BackupManagerProxy mBackupManagerProxy; private final FrameworkFacade mFrameworkFacade; + private final MacAddressUtil mMacAddressUtil; + private final Mac mMac; private boolean mRequiresApBandConversion = false; WifiApConfigStore(Context context, WifiInjector wifiInjector, Handler handler, @@ -143,6 +147,12 @@ public class WifiApConfigStore { filter.addAction(ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT); mContext.registerReceiver( mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler); + mMacAddressUtil = mWifiInjector.getMacAddressUtil(); + mMac = mMacAddressUtil.obtainMacRandHashFunctionForSap(Process.WIFI_UID); + if (mMac == null) { + Log.wtf(TAG, "Failed to obtain secret for SAP MAC randomization." + + " All randomized MAC addresses are lost!"); + } } private final BroadcastReceiver mBroadcastReceiver = @@ -413,7 +423,13 @@ public class WifiApConfigStore { config = new WifiConfiguration(config); if (config.BSSID == null && context.getResources().getBoolean( R.bool.config_wifi_ap_mac_randomization_supported)) { - config.BSSID = MacAddress.createRandomUnicastAddress().toString(); + MacAddress macAddress = mMacAddressUtil.calculatePersistentMac(config.SSID, mMac); + if (macAddress == null) { + Log.e(TAG, "Failed to calculate MAC from SSID. " + + "Generating new random MAC instead."); + macAddress = MacAddress.createRandomUnicastAddress(); + } + config.BSSID = macAddress.toString(); } return config; } diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 958a9f1b0..82d799081 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -572,7 +572,7 @@ public class WifiConfigManager { mRandomizedMacAddressMapping.remove(config.getSsidAndSecurityTypeString()); } } - return mMacAddressUtil.calculatePersistentMacForConfiguration(config, mMac); + return mMacAddressUtil.calculatePersistentMac(config.getSsidAndSecurityTypeString(), mMac); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/MacAddressUtilTest.java b/tests/wifitests/src/com/android/server/wifi/MacAddressUtilTest.java index 331725c14..1e04c8643 100644 --- a/tests/wifitests/src/com/android/server/wifi/MacAddressUtilTest.java +++ b/tests/wifitests/src/com/android/server/wifi/MacAddressUtilTest.java @@ -49,23 +49,21 @@ public class MacAddressUtilTest extends WifiBaseTest { } /** - * Verifies that calculatePersistentMacForConfiguration valid randomized MACs. + * Verifies that calculatePersistentMac generate valid randomized MACs. */ @Test - public void testCalculatePersistentMacForConfiguration() { + public void testCalculatePersistentMac() { // verify null inputs - assertNull(mMacAddressUtil.calculatePersistentMacForConfiguration(null, null)); + assertNull(mMacAddressUtil.calculatePersistentMac(null, null)); Random rand = new Random(); // Verify that a the MAC address calculated is valid for (int i = 0; i < 10; i++) { - WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); - byte[] bytes = new byte[32]; rand.nextBytes(bytes); when(mMac.doFinal(any())).thenReturn(bytes); - MacAddress macAddress = mMacAddressUtil.calculatePersistentMacForConfiguration( - config, mMac); + MacAddress macAddress = mMacAddressUtil.calculatePersistentMac( + "TEST_SSID_AND_SECURITY_TYPE_" + i, mMac); assertTrue(WifiConfiguration.isValidMacAddressForRandomization(macAddress)); } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java index 3d78e1e46..f150bf797 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java @@ -84,6 +84,8 @@ public class WifiApConfigStoreTest extends WifiBaseTest { private static final String TEST_STRING_UTF8_WITH_32_BYTES = "ΣωκράτηςΣωκράτης"; private static final String TEST_STRING_UTF8_WITH_33_BYTES = "一片汪洋大海中的一條魚"; private static final String TEST_STRING_UTF8_WITH_34_BYTES = "Ευπροσηγοροςγινου"; + private static final MacAddress TEST_RANDOMIZED_MAC = + MacAddress.fromString("d2:11:19:34:a5:20"); @Mock private Context mContext; @Mock private WifiInjector mWifiInjector; @@ -96,6 +98,7 @@ public class WifiApConfigStoreTest extends WifiBaseTest { @Mock private ApplicationInfo mMockApplInfo; private BroadcastReceiver mBroadcastReceiver; @Mock private NotificationManager mNotificationManager; + @Mock private MacAddressUtil mMacAddressUtil; private ArrayList<Integer> mKnownGood2GChannelList; @Before @@ -132,6 +135,8 @@ public class WifiApConfigStoreTest extends WifiBaseTest { mKnownGood2GChannelList = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); mRandom = new Random(); + when(mWifiInjector.getMacAddressUtil()).thenReturn(mMacAddressUtil); + when(mMacAddressUtil.calculatePersistentMac(any(), any())).thenReturn(TEST_RANDOMIZED_MAC); } @After @@ -591,14 +596,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest { WifiConfiguration baseConfig = new WifiConfiguration(); WifiApConfigStore store = createWifiApConfigStore(); - WifiConfiguration config1 = store.randomizeBssidIfUnset(mContext, baseConfig); - WifiConfiguration config2 = store.randomizeBssidIfUnset(mContext, baseConfig); - - assertThat(config1.BSSID).isNotNull(); - assertThat(config2.BSSID).isNotNull(); - MacAddress mac1 = MacAddress.fromString(config1.BSSID); - MacAddress mac2 = MacAddress.fromString(config2.BSSID); - assertThat(mac1).isNotEqualTo(mac2); + WifiConfiguration config = store.randomizeBssidIfUnset(mContext, baseConfig); + + assertEquals(TEST_RANDOMIZED_MAC.toString(), config.BSSID); } @Test diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index e99224512..895a169a1 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -222,8 +222,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { .thenReturn(false); when(mWifiInjector.getCarrierNetworkConfig()).thenReturn(mCarrierNetworkConfig); when(mWifiInjector.getMacAddressUtil()).thenReturn(mMacAddressUtil); - when(mMacAddressUtil.calculatePersistentMacForConfiguration(any(), any())) - .thenReturn(TEST_RANDOMIZED_MAC); + when(mMacAddressUtil.calculatePersistentMac(any(), any())).thenReturn(TEST_RANDOMIZED_MAC); mTelephonyUtil = new TelephonyUtil(mTelephonyManager, mSubscriptionManager); createWifiConfigManager(); |